首先,來看一下介面簽名加密規則
1.需要參於簽名的引數:
a. 在請求引數列表中,除去 cliSign 引數外,其他需要使用到的引數皆是要簽名的引數。
2.生成簽名字串
a. 沒有值的引數無需傳遞,也無需包含到待簽名資料中
b. 簽名資料應該是原生值而不是 encoding 之後的值
c. 若遇引數值為陣列時,請以char=7對應字元進行分割此引數的多個值
d. 按簽名引數 a 到 z 的順序排序("&"是分割開出多個引數)
簽名引數字串如下:
params = channel =0&password=abc&userid=13876
pass = md5(params + appkey).toLowerCase() 注:“+”加與為字串相連符,不在簽名字元裡,appkey為祕鑰,為雙方平臺約定字元
加密後cliSign = pass.substring(5, 21);全部小寫後,獲取前8到24位共16位傳到服務端;
e. 針對部分CDN介面若有傳中文,客戶端請在對中文URLEncoder後加密
3.開發測試環境簽名金鑰:
appkey="test888"
beanshell程式碼如下:
import org.apache.commons.codec.digest.DigestUtils;
//業務欄位
String accessToken = vars.get("access_token");
String userId = vars.get("user_id");
String videoId = vars.get("videoId");
//POST/get請求公共引數
String appId = vars.get("appId");
String brand = vars.get("brand");
String channel = vars.get("channel");
String device = vars.get("device");
String platform = vars.get("platform");
String sysVersion = vars.get("sysVersion");
String times = vars.get("times");
String version = vars.get("version");
String appkey = vars.get("appkey");
//將簽名傳給cliSign引數,使用treemap,可自動進行排序
Map map = new TreeMap();
map.put("accessToken", accessToken);
map.put("userId", userId);
map.put("videoId", videoId);
map.put("appId", appId);
map.put("brand", brand);
map.put("channel", channel);
map.put("device", device);
map.put("platform", platform);
map.put("sysVersion", sysVersion);
map.put("times",times);
map.put("version", version);
//URLEncoder.encode(value, "UTF-8") 對中文進行格式化,這裡不需要
StringBuffer sb = new StringBuffer();
for (Map.Entry entry : map.entrySet()) {
sb.append(entry.getKey() + "=" + entry.getValue());
sb.append("&");
}
String s = sb.toString();
if (s.endsWith("&")) {
s = org.apache.commons.lang.StringUtils.substringBeforeLast(s, "&");
}
log.info("Map轉換為URL編碼"+s);
String str1 = s+appkey;
log.info("待加密字串為:"+str1);
//進行md5加密
String pass = DigestUtils.md5Hex(str1).toLowerCase();
log.info("加密後的值:"+pass);
//擷取前8到21位為簽名
String sign = pass.substring(5, 21);
log.info("最終簽名為:"+sign);
//將簽名傳給cliSign引數
vars.put("cliSign",sign);
技巧總結
- 將可能發生變動的引數均進行引數化,然後使用vars.put()方法獲取,這樣以後就不需要再修改beanshell中的程式碼
- 由於每個介面都需要用一個beanshell來獲取簽名,最好將業務引數和公共引數分開,便於修改和檢視
- 對於關鍵變數,將其列印到日誌中,方便定位問題,比如我之前碰到的問題:
a. 不確定拼接後的引數是否正確、順序是否正確,是否需要用URLEncoder進行轉碼或者獲取引數時出錯等,只有列印出來後才能知道;
b.不確定加密後的值是否正確,有可能與開發使用的加密方法不一致;
c. 不確定擷取後,最終簽名是否正確
簽名機制就是這樣,每一步都不能出錯,需要步步為營,抽絲剝繭。找到是哪一步出的問題
附錄:URL線上轉碼測試
本次的坑
- 從csv檔案中讀取的引數,自動加上了“”,導致最終傳參不正確(在csv檔案配置中將【是否允許帶引號】設定為true即可);
- 對引數進行了URLEncoder轉碼,後來發現不需要;
- 能複製就不要手寫,有的時候引數名就錯了一個字母,但是找起來真的很頭疼;
- 如果可以,最好找開發用一個實際的介面進行詳細的示例,只看文件會跑偏。