1. 程式人生 > 實用技巧 >介面加密,Zuul閘道器解碼轉發

介面加密,Zuul閘道器解碼轉發

如果系統明文傳輸的資料會被不明身份的人用抓包工具抓取,從而威脅系統和資料的安全性,那麼就要使用加密的方式來對資料介面進行加密 加密方式:   摘要演算法:加密方式不需要祕鑰,加密後的資料無法被解密,只有輸入相同的明文資料經過相同的訊息摘要演算法才能得到相同密文   對稱加密:明文資料通過祕鑰進行加密,傳輸到後臺,在通過相同的密碼進行解密操作,缺點就是如何把祕鑰安全的傳輸到解密者   非對稱加密:數字簽名使用私鑰生成簽名,使用公鑰驗證簽名 通過公鑰加密傳輸,通過私鑰進行解密操作 祕鑰生成工具:OpenSSlL   使用OpenSSl生成rsa金鑰對,金鑰長度介於 512 - 65536 之間(JDK 中預設長度是1024),且必須是64 的倍數。金鑰的常用檔案格式有pem(文字儲存)或者der(二進位制儲存),當使用Java API生成RSA金鑰對時,公鑰以X.509格式編碼,私鑰以PKCS#8格式編碼,RSA使用pkcs協議定義金鑰的儲存結構等內容 通過OpenssL生成的私鑰還要經過OpenSSL進行PKCS#8的編碼操作,JAVA需要使用的私鑰需要經過PKCS#8編碼   生成祕鑰對的方法可以參考這篇帖子
猛點我
!
一般直接通過URL直接訪問後端介面,實不可取的,通過Zuul進行解密轉發,從而保證安全性 Zuul YML配置檔案 


server:
  port: #Zuul的埠號
spring:
  application:
    name: #Zuul的name
zuul:
  routes: 
    user_name: #user微服務的名稱
      path: /user/** #配置請求URL的請求規則
      serviceId: user_name #指定Eureka註冊中心中的服務id
      strip-prefix: true
      sentiviteHeaders:
      customSensitiveHeaders: true   #讓zuul處理cookie和重定向
#Eurkea註冊發現中心
eureka:
  client:
    service-url:
      defaultZone: http://127.0.0.1:6868/eureka/
  instance:
    prefer-ip-address: true
Zuul.pom檔案配置
 <dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        </dependency>
        <dependency>
            <groupId
>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-zuul</artifactId> </dependency> </dependencies>

ZuuL啟動類

@SpringBootApplication
@EnableEurekaClient  //註冊發現中心 
@EnableZuulProxy   //閘道器過濾器
public class EncryptApplication {
    public static void main(String[] args) {
        SpringApplication.run(EncryptApplication.class);
    }
}

//祕鑰
public class RsaKeys {
    //伺服器公鑰
    private static final String serverPubKey = "使用OpenSSL生成的公鑰";

    //伺服器私鑰(經過pkcs8格式處理)
    private static final String serverPrvKeyPkcs8 = "使用OpenSSL生成的私鑰經過pkcs8格式處理";

    public static String getServerPubKey() {
        return serverPubKey;
    }

    public static String getServerPrvKeyPkcs8() {
        return serverPrvKeyPkcs8;
    }
}
//RSA解碼加密,網上搜一下,很多
@Service("RsaService")
public class RsaServiceImpl implements RsaService {
    /***
     * RSA解密
     *
     * @param encryptData
     * @return
     * @throws Exception
     */
    public String RSADecryptDataPEM(String encryptData, String prvKey) throws Exception {
    	byte[] encryptBytes = encryptData.getBytes();
        byte[] prvdata = RSA.decryptByPrivateKey(Base64Utils.decode(encryptData), prvKey);

        String outString = new String(prvdata, "UTF-8");
        return outString;
    }
    
    @Override
	public String RSADecryptDataBytes(byte[] encryptBytes, String prvKey)
			throws Exception {
		// TODO Auto-generated method stub
    	byte[] prvdata = RSA.decryptByPrivateKey(encryptBytes, prvKey);
        String outString = new String(prvdata, "utf-8");
        return outString;
	}

    /***
     * RSA加密
     *
     * @param data
     * @return
     * @throws Exception
     */
    public String RSAEncryptDataPEM(String data, String pubKey) throws Exception {

        byte[] pubdata = RSA.encryptByPublicKey(data.getBytes("UTF-8"), pubKey);
        String outString = new String(Base64Utils.encode(pubdata));

        return outString;
    }

	@Override
	public String getRsaAlgorithm() {
		// TODO Auto-generated method stub
		KeyFactory keyFactory = null;
		try {
			keyFactory = KeyFactory.getInstance("RSA");
		} catch (NoSuchAlgorithmException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return keyFactory.getAlgorithm();
	}

	
}
建立filter過濾器繼承ZuulFilter
@Component
public class RSARequestFilter extends ZuulFilter {
   //RSA加密解密介面 
  @Autowired private RsaService rsaService; @Override public String filterType() { //過濾器在什麼時候執行,在解密之前執行 return FilterConstants.PRE_TYPE; } @Override public int filterOrder() { //執行順序 return FilterConstants.PRE_DECORATION_FILTER_ORDER + 1; } @Override public boolean shouldFilter() { //是否使用過濾器 return true; } @Override public Object run() throws ZuulException { //獲取Conext物件應用上下文, 從中獲取req,res物件 RequestContext cxt = RequestContext.getCurrentContext(); HttpServletRequest request = cxt.getRequest(); HttpServletResponse response = cxt.getResponse(); //存放加密資料的變數 String requestData = null; String decodeData = null; try { //從req中獲取請求的內容,獲取通過公鑰加密後的資料, ServletInputStream inputStream = request.getInputStream(); //通過流的工具類,吧流的資訊轉換成string型別的,指定字符集utf-8,得到公鑰加密後的資料 requestData = StreamUtils.copyToString(inputStream, Charsets.UTF_8); System.out.println("加密後的:" + requestData); if (!Strings.isNullOrEmpty(requestData)) { //如果得到的資料不為空,進行解密操作 decodeData = rsaService.RSADecryptDataPEM(requestData, RsaKeys.getServerPrvKeyPkcs8()); System.out.println("解密後的:" + decodeData); } //吧解密後的資料轉發給對應服務request if (!Strings.isNullOrEmpty(decodeData)) { byte[] bytes = decodeData.getBytes(); cxt.setRequest(new HttpServletRequestWrapper(request) { @Override public ServletInputStream getInputStream() { return new ServletInputStreamWrapper(bytes); } @Override public int getContentLength() { return bytes.length; } @Override public long getContentLengthLong() { return bytes.length; } }); }   //進行轉碼操作 cxt.addZuulRequestHeader("Content-Type" , MediaType.APPLICATION_JSON_VALUE + ";charset=UTF-8"); } catch (Exception e) { e.printStackTrace(); } return null; } }

  在POSTMan測試前,可以先成加密後的介面密文, 比如http://127.0.0.1:9002/user/user/2 本機的9002是你的Zuul閘道器埠,訪問配置檔案中要攔截的介面,解密後,轉發到user微服務查詢id 等於2的使用者

測試類

@RunWith(SpringJUnit4ClassRunner.class)
@SpringBootTest(classes = EncryptApplication.class)
public class EncryptTest {
    @Autowired
    private RsaService rsaService;
    @Test
    public void genEncryptDataByPubKey() {
        String data = "{\"需要加密的明文\":\"需要加密的明文\"}";
        try {
            String encData = rsaService.RSAEncryptDataPEM(data, RsaKeys.getServerPubKey());
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    
    @Test
    public  void  pojie() throws Exception {
        String mima = "明文加密後的祕鑰";
        //呼叫解密
        String s = rsaService.RSADecryptDataPEM(mima, RsaKeys.getServerPrvKeyPkcs8());
        System.out.println(s);
    }
}

  

寫的不是特別好,主要是自己學習用