記錄下jmeter處理接口RSA+base64加密的學習過程


最近項目接口采用了RSA加密,之前的jmeter自動化腳本不能沿用了,我決定用beanshell來處理加密和解密完成自動化。

通過一天的折騰,加上開發大兄弟的援助,我這個java零基礎的測試小白把rsa的加密解密方法搞出來了,idea運行成功加密和解密,代碼如下:

 1  1 package com.example.code.demo;
 2  2 
 3  3 import org.apache.commons.codec.binary.Base64;
 4  4 
 5  5 import javax.crypto.BadPaddingException;
 6  6 import javax.crypto.Cipher;
 7  7 import javax.crypto.IllegalBlockSizeException;
 8  8 import java.io.ByteArrayOutputStream;
 9  9 import java.io.IOException;
10 10 import java.nio.charset.Charset;
11 11 import java.nio.charset.StandardCharsets;
12 12 import java.security.KeyFactory;
13 13 import java.security.interfaces.RSAPrivateKey;
14 14 import java.security.interfaces.RSAPublicKey;
15 15 import java.security.spec.PKCS8EncodedKeySpec;
16 16 import java.security.spec.X509EncodedKeySpec;
17 17 
18 18 public class RsaTool {
19 19 
20 20     /** RSA最大加密明文大小 */
21 21     private static final int MAX_ENCRYPT_BLOCK = 245;
22 22     private static final Charset CHARSET = StandardCharsets.UTF_8;
23 23     /** RSA最大解密密文大小 */
24 24     private static final int MAX_DECRYPT_BLOCK = 256;
25 25 //    公鑰加密
26 26     public  String encrypt(String str, String publicKey) throws Exception {
27 27         //base64編碼的公鑰
28 28         byte[] decoded = Base64.decodeBase64(publicKey);
29 29         RSAPublicKey pubKey = (RSAPublicKey) KeyFactory.getInstance("RSA").generatePublic(new X509EncodedKeySpec(decoded));
30 30         //RSA加密
31 31         Cipher cipher = Cipher.getInstance("RSA");
32 32         cipher.init(Cipher.ENCRYPT_MODE, pubKey);
33 33         byte[] data = doSegmentFinal(cipher, str.getBytes(CHARSET), MAX_ENCRYPT_BLOCK);
34 34 //        String outStr = Base64.encodeBase64String(cipher.doFinal(str.getBytes(StandardCharsets.UTF_8)));
35 35         String outStr = Base64.encodeBase64String(data);
36 36 //        String str = new String(outStr)
37 37         System.out.println("這是公鑰加密后的字符: "+outStr);
38 38         return outStr;
39 39     }
40 40 //    私鑰解密
41 41     public  String decrypt(String str, String privateKey) throws Exception {
42 42         //64位解碼加密后的字符串
43 43         byte[] inputByte = Base64.decodeBase64(str.getBytes(StandardCharsets.UTF_8));
44 44         //base64編碼的私鑰
45 45         byte[] decoded = Base64.decodeBase64(privateKey);
46 46         RSAPrivateKey priKey = (RSAPrivateKey) KeyFactory.getInstance("RSA").generatePrivate(new PKCS8EncodedKeySpec(decoded));
47 47         //RSA解密
48 48         Cipher cipher = Cipher.getInstance("RSA");
49 49         cipher.init(Cipher.DECRYPT_MODE, priKey);
50 50         byte[] data = doSegmentFinal(cipher,inputByte, MAX_DECRYPT_BLOCK);
51 51 //        String outStr = new String(cipher.doFinal(inputByte));
52 52         String outStr =  new String(data,StandardCharsets.UTF_8);
53 53         System.out.println("這是私鑰解密后的字符: "+outStr);
54 54         return outStr;
55 55     }
56 56     private static byte[] doSegmentFinal(Cipher cipher, byte[] data, int segmentLength)
57 57             throws IOException, BadPaddingException, IllegalBlockSizeException {
58 58         try (ByteArrayOutputStream out = new ByteArrayOutputStream()) {
59 59             int inputLen = data.length;
60 60             int offSet = 0;
61 61             byte[] cache;
62 62             int i = 0;
63 63 
64 64             while (inputLen - offSet > 0) {
65 65                 if (inputLen - offSet > segmentLength) {
66 66                     cache = cipher.doFinal(data, offSet, segmentLength);
67 67                 } else {
68 68                     cache = cipher.doFinal(data, offSet, inputLen - offSet);
69 69                 }
70 70                 out.write(cache, 0, cache.length);
71 71                 i++;
72 72                 offSet = i * segmentLength;
73 73             }
74 74             return out.toByteArray();
75 75         }
76 76     }
77 77     public String msg(){
78 78         return "never mind scandal and liber";
79 79     }
80 80 }
RSA_code

接下來先試試用jmeter引用這個java文件

哦豁,報錯了

 去找下萬能的度娘,看看這是個啥問題.

百度了一大堆文章也只有一些無光痛癢的東西,所以我打算換個方式,用jmeter引用jar包再調用解密方法。

之前引用fasijson包解析過json數據,操作本身還是不算麻煩。

首先在idea里把項目打成jar包,然后把jar包路徑配置到jmeter的任務里。(也可以將jar包放到jmeter/bin/lib/ext目錄下直接引用。或者是修改properties文件,建立一個單獨的依賴包目錄,這類教程網上很多)

  在beanshell取樣器中引用jar包里的類,調用靜態加密方法。 

依然在報錯,沒有找到RsaTool類.這就讓人很難受了.

再次去拜訪度娘,看了十幾個帖子,依然沒找到有效辦法,我就在想是不是這個java文件本身有問題。

我創建java項目時使用了spring boot這個框架,對這個框架的機制我完全不了解,我擔心jemter沒有識別到這框架的結構,於是新建了一個相對簡潔方便一點的maven項目,

可是打包調用后依然遇到了以上問題。最后我決定返璞歸真,建立一個最初始的java項目試試。

 

欸!好像能行

方法能夠成功調用,返回數據也是正常的。看來rsa加密沒什么問題了,接下就是要根據接口文檔處理入參和出參了。

 

請求接口的參數的規范是每個請求中將所有字段一起加密,作為data的值進行請求。

  1. {
  2. "data": "加密后的密文"
  3. }

我大概的請求思路是csv文檔記錄每一個字段的名字和值,自己再寫一個java方法把字段拼接為json字符串,將json字符串傳入rsa加密方法獲取加密后的str,使用vars.get方法將str加載到jmeter變量parameters中,在http的post請求中調用${parameter},即可進行加密后的請求。

 

響應接口的參數規范和請求類似,只是多加了兩個字段

  1. {
  2. "code": "0000",
  3. "message": "成功",
  4. "data": {
  5. "verifyCode": "000000"
  6. }
  7. }

接口會有參數關聯,比如token和一些id。此時就需要從響應的data中拿到加密后的字符串,進行解析,拿到需要的數據。

大致思路是:用jemter自帶的json提取器,將data的值及加密后的字符穿作為變量提取出來。再傳入rsa解密方法,獲得真實的json響應數據。利用alibaba的fastjson包解析數據,提取目標字段的值用於下一步的傳參或者是斷言(此處存疑,csv中也有參數,以誰為准)。

 

然而jmeter拿到加密后的字符串后請求服務器又雙叒叕報錯了,這次是服務返回json格式錯誤。

我查看了請求的參數,發現請求參數的加密字符串部分特殊字符被url編碼了。我懷疑這個編碼會有影響,嘗試使用了

${__urldecode('${parameter}')}方法將參數解碼,然並卵。

 

 

 

 

哈哈哈哈哈哈哈哈哈,然后我嘗試了將參數寫在了【消息體數據】里,All Green,跑通了。

 

原來POST請求下面兩個填寫參數的地方是有區別的,在【參數】中填寫請求參數會構造出類似GET的請求,格式是這樣的:ulr?parameter1&parameter2,也就是我們平時在瀏覽器地址框中看到的鏈接地址,這樣當然會被URL編碼啊 kora!

我們來看看這兩種填寫參數的方式的區別:

在【參數】中填寫請求數據

 

 

 

在【消息體】中填寫請求數據

 

 

 

 

准備工作已經就緒,接下來打算讀取CSV中的變量進行參數化請求。

1 import main.java.RsaCode.Rsa;
2 log.info("+++something for nothing+++");
3 //parameter是從csv中讀取出來的參數 ,格式為{"phone":"13611111111"}
4 String postData = Rsa.encrypt(${parameter},"${pubKey}");
5 vars.put("postData",postData);
調用加密函數

運行,穩定報錯

2019-12-17 15:02:08,415 ERROR o.a.j.u.BeanShellInterpreter: Error invoking bsh method: eval In file: inline evaluation of: ``//source("D:/docs/java_proj/RsaCode/src/main/java/RsaCode/Rsa.java"); import mai . . . '' Encountered "( {" at line 9, column 30.

看來是JSON格式中雙引號的問題,因為java字符串只能用雙引號表示,不像python可以使用單引號/雙引號/三引號。

查閱了資料,發現使用beanshell自帶的vars.put()方法可以避免這個問題。

1 import main.java.RsaCode.Rsa;
2 log.info("+++something for nothing+++");
3 //parameter是從csv中讀取出來的參數 ,格式為{"phone":"13611111111"}
4 String enData = vars.get("parameter");
5 String postData = Rsa.encrypt(enData,"${pubKey}");
6 vars.put("postData",postData);
調用加密函數·改

vars.put("變量名”)是將jemter線程中的變量加載到beanshell定義的變量中

 

在數據驅動的過程中又遇到了新的問題,有多行內容的csv文件,在jmeter線程組中僅執行一次,不能遍歷所有行的內容。CSV data set config 本身的設置應該是沒問題的,因為之前有成功的案例。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM