Step 1. 構造源串
源串是由3部分內容用“&”拼接起來的:
HTTP請求方式 & urlencode(uri) & urlencode(a=x&b=y&...)
源串構造步驟如下:
第1步:將請求的URI路徑進行URL編碼(URI不含host,URI示例:/v3/user/get_info)。
<font color="red">請開發者關注:URL編碼注意事項,否則容易導致后面簽名不能通過驗證。</font>
第2步:<font color="red">將除“sig”外的所有參數</font>按key進行字典升序排列。
注:除非OpenAPI文檔中特別標注了某參數不參與簽名,否則除sig外的所有參數都要參與簽名。
第3步:將第2步中排序后的參數(key=value)用&拼接起來,并進行URL編碼。
<font color="red">請開發者關注:URL編碼注意事項,否則容易導致后面簽名不能通過驗證。</font>
第4步:將HTTP請求方式(GET或者POST)以及第1步和第3步中的字符串用&拼接起來。
注:Java_SDK_V3.0.6僅支持POST方式,如果用GET可能導致一直計算sig不正確。
Step 2. 構造密鑰
得到密鑰的方式:在應用的appkey末尾加上一個字節的“&”,即appkey&,例如:228bf094169a40a3bd188ba37ebe8723&
Step 3. 生成簽名值
使用HMAC-SHA1加密算法,使用Step2中得到的密鑰對Step1中得到的源串加密。
(注:一般程序語言中會內置HMAC-SHA1加密算法的函數,例如PHP5.1.2之后的版本可直接調用hash_hmac函數。)然后將加密后的字符串經過Base64編碼。
(注:一般程序語言中會內置Base64編碼函數,例如PHP中可直接調用 base64_encode() 函數。)得到的簽名值結果如下:
FdJkiDYwMj5Aj1UG2RUPc83iokk=
public class BasicParamsInterceptor implements Interceptor {
public static String TAG="BasicParamsInterceptor";
private BasicParamsInterceptor() {
}
@Override
public Response intercept(Chain chain) throws IOException {
Request request = chain.request();
Request.Builder requestBuilder = request.newBuilder();
//===========給參數進行加密 start===================
String signParam="";
if("POST".equals(request.method())){
String url="你的請求url";
String encodeURL="";//URL編碼后的請求url
String encodeSortParams="";//URL編碼后的升序參數體
HashMap<String, String> paramsMap =new HashMap<String, String>();
//step1.1 將請求的URI路徑進行URL編碼
encodeURL=URLEncoder.encode(url,"utf-8");
Log.d(TAG,"url="+url);
Log.d(TAG,"encode_url="+ encodeURL);
StringBuilder sb = new StringBuilder();
if (request.body() instanceof FormBody) {
FormBody body = (FormBody) request.body();
int bodySize=body.size();
for (int i = 0; i < bodySize; i++) {
paramsMap.put(body.encodedName(i),body.encodedValue(i));
sb.append(body.encodedName(i) + "=" + body.encodedValue(i) + ",");
}
sb.delete(sb.length() - 1, sb.length());
Log.d(TAG, "║ RequestParams:{"+sb.toString()+"}");
Collection<String> keyset= paramsMap.keySet();
List<String> list = new ArrayList<String>(keyset);
//step1.2 對key鍵值按字典升序排序
Collections.sort(list);
StringBuilder sortParams = new StringBuilder();
int sortParamSize=list.size();
//step1.3 將第2步中排序后的參數(key=value)用&拼接起來,并進行URL編碼。
for (int i = 0; i < sortParamSize; i++) {
sortParams.append(list.get(i)+"="+paramsMap.get(list.get(i)));
if(i!=sortParamSize-1){
sortParams.append("&");
}
}
Log.d(TAG,"數據字典升序后:key鍵值="+sortParams.toString());
encodeSortParams=URLEncoder.encode(sortParams.toString(),"utf-8");//進行URL編碼的 key鍵值
Log.d(TAG,"數據字典升序并encode="+encodeSortParams);
//step1.4 將HTTP請求方式(GET或者POST)以及第1步和第3步中的字符串用&拼接起來。
StringBuilder bufferStep1=new StringBuilder();
bufferStep1.append(request.method());
bufferStep1.append("&");
bufferStep1.append(encodeURL);
bufferStep1.append("&");
bufferStep1.append(encodeSortParams);
Log.d(TAG,"拼接后的step1="+bufferStep1.toString());
try {
//step 2
String key="你的key"+"&"
//step3
signParam=Util.HMACSha1(bufferStep1.toString(),key);
Log.d(TAG,"signParam="+signParam);
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (InvalidKeyException e) {
e.printStackTrace();
}
}
}
paramsMap.put("sign",signParam.trim());
//===========給參數進行加密 end===================
}
/**
* 獲取 hmacSha1 并返回Base64編碼后的字符串
*
* @param base
* @param key
* @return
* @throws NoSuchAlgorithmException
* @throws InvalidKeyException
*/
public static String HMACSha1(String base, String key) throws NoSuchAlgorithmException, InvalidKeyException {
if (TextUtils.isEmpty(base) || TextUtils.isEmpty(key)) {
return "";
}
String type = "HmacSHA1";
SecretKeySpec secret = new SecretKeySpec(key.getBytes(), type);
Mac mac = Mac.getInstance(type);
mac.init(secret);
byte[] digest = mac.doFinal(base.getBytes());
return Base64.encodeToString(digest, Base64.DEFAULT);
}