權益需求對接中,公司跟第三方公司合作,有時我們可能作為甲方,提供接口給對方,有時我們也作為乙方,調對方接口,這就需要API使用簽名方法(Sign)對接口進行鑒權。每一次請求都需要在請求中包含簽名信息, 以驗證用戶身份,不然任何人都可以調我們公司的接口,會導致安全隱患。
思路:在接口請求參數都帶上appKey,簽名sign和時間戳timestamp等字段。
假如我們是甲方時,那么需要讓乙方在目標網站上申請或者給乙方提供安全憑證(appKey和appSecret),其中 appKey是用於標識 API 調用者的身份,appSecret是用於加密簽名字符串和服務器端驗證簽名字符串的密鑰。appSecret必須嚴格保管。避免泄露。
乙方(對方)需要做
根據甲方(我們)提供appSecret和需要傳的特定參數生成的簽名sign,最后在接口的url參數拼接上,簽名sign,時間戳timestamp和appKey等參數。
具體步驟如下:
1. 對參數進行排序和拼接
首先對請求參數按參數名做字典序升序(自然順序)排列,然后格式化特定的形式,例如 k=v的形式,同時參數間使用"&"拼接在一起,或者kv的形式,不用"&"拼接的形式(注意不包括簽名Sign參數,v為原始值而非url編碼后的值)。
示例 采用k=v的形式,同時參數間使用"&"拼接在一起
appkey=00159&from=51916&phone=13612549848&thirdOrderId=768169123×tamp=2020-10-22 17:39:08&ver=3.4
2. 使用特定的加密算法進行加密(Md5,SHA),再進行大小寫格式化等操作
String sig = MD5Utils.EncoderByMd5(appSecret + “參數進行排序和拼接后的字符串”+ appSecret).toLowerCase().substring(0, 30);
3. url拼接簽名sign,時間戳timestamp和appKey等參數
StringBuilder stringBuilder = new StringBuilder(url); if (url.contains("?")) { stringBuilder.append("&client_id=").append(clientId) .append("&ext_user_id=").append(phead.getUserId()) .append("&sign=").append(sign) .append("×tamp=").append(timestamp) .append("&phone=").append(phone) .append("&callback_info=").append(phead.getUserId()); }
項目實戰
示例1
示例2
我們(甲方)要做
拿到對方請求我們傳過來的參數中的簽名sign和appKey和時間戳等字段,然后通過appKey去獲得對應的密碼appSecret(這兩個參數appKey和appSecret是我們定義后給乙方的),我們通過和乙方一樣的方式生成簽名sign2,最后比較對方傳過來的sign值和我們以同樣方式生成得到的sign2是不是一致,一致簽名驗證就通過,不一致簽名就是失敗;
注意:有了簽名,基本上數據的合法性就得到了保障。只要壞人沒有秘鑰就無法偽造調用方的請求。但壞人依然可以截取調用方的請求,不停的發送給服務端,造成服務端資源緊張、數據錯誤等不好的結果。為了防止同樣的請求多次發送,我們往往還要求調用方提供一個唯一的序列號,比如UUID、時間戳之類的。服務端需要在收到請求的第一時間校驗該唯一序列號。我們可以通過spring的切面或者攔截器來做。
參考/好文
https://www.web3.xin/index/article/156.html