通過Postman實現API閘道器的請求籤名與除錯
通過Postman實現API閘道器的請求籤名與除錯
1. 前言
Postman是一個非常強大的HTTP發包測試工具, 目前Postman已經提供了Windows/Mac/Linux系統的客戶端的下載,使用很方便。不過API閘道器的除錯,需要對HTTP請求進行簽名才能呼叫,無法使用簡單的curl
等發包工具完成,但我們可以使用Postman工具提供的Pre-request Script指令碼來實現API閘道器的簽名功能,實現API的除錯功能,本文主要介紹。
2. API閘道器簽名演算法介紹
API閘道器的簽名機制詳細可以參考官網文件,這裡簡要介紹一下。
API閘道器的簽名需要通過API閘道器的AppKey和AppSecret進行,Key/Secret可以在API閘道器的控制檯上獲得,並確保API已經發布,並且針對特定的APP做了授權操作。
針對一個普通請求,API閘道器的簽名過程如下
2.1. 新增以下頭用於輔助簽名與安全認證
- Date: 日期頭
- X-Ca-Key:{AppKey}
- X-Ca-Nonce:API呼叫者生成的 UUID, 實現防重放功能
- Content-MD5: 當請求Body為非Form表單時,用於校驗Body是否被篡改,
2.2. 組織需要簽名的字串StringToSign
{HTTPMethod} + "
" +
{Accept} + "
" +
{Content-MD5} + "
"
{Content-Type} + "
" +
{Date} + "
" +
{SignatureHeaders} +
{UrlToSign}
- Accept、Content-MD5、Content-Type、Date 如果為空也需要新增換行符”n”
- 只有From為非表單的方式才需要計算Content-MD5,計算方法為
base64Encode(md5(body.getBytes("UTF-8"))
- SignatureHeaders: 以
{HeaderName}:{HeaderValue} + "
的方式按照字串順序從小到大順序新增, 建議加入簽名的頭為
"X-Ca-Key
,X-Ca-Nonce
, 其他頭客戶端實現可自行選擇是否加入簽名。 - UrlToSign: 將所有的Form欄位和QueryString欄位放在一起按照
Name
進行排序,如果Content-Type
不是application/x-www-form-urlencoded
型別則不拆開Form欄位。將排序好的鍵值對加到Path
後面得到UrlToSign
, 例如請求/demo?c=1&a=2
, Form為b=3
則UrlToSign
=/demo?a=2&b=3&c=1
2.3. 計算簽名並附加簽名相關Headers
目前推薦使用HMacSHA256
演算法計算簽名,簽名的計算需要appSecret,計算方法為:
signature = base64(hmacSHA256(stringToSign.getBytes("UTF-8), appSecret))
, 計算完畢後還需要新增以下Headers:
- 新增Header:
X-Ca-Siguature:{signature}
- 新增Header:
X-Ca-SignatureMethod:HmacSHA256
- 新增Header:
X-Ca-SignatureHeaders:X-Ca-Key,X-Ca-Nonce
2.4. 簽名錯誤排查方法
- 當簽名校驗失敗時,API閘道器會將服務端的
StringToSign
放到HTTP應答的Header中返回到客戶端,Key為:X-Ca-Error-Message
,只需要將本地計算的StringToSign
與服務端返回的StringToSign
進行對比即可找到問題,注意服務端返回的StringToSign
將回車替換為了#
,對比是請注意; - 如果服務端與客戶端的一致請檢查用於簽名計算的金鑰是否正確
3. 使用Pre-request Script實現簽名演算法
根據上一節的描述,實現API閘道器除錯的關鍵問題在於如何實現請求籤名,Postman
提供了可以通過JavaScript進行定製的, 通過閱讀Pre-request Script的開發文件, 我們可以通過Pre-request Script指令碼
實現API閘道器的簽名功能。
3.1. 使用全域性變數預製簽名需要新增的頭
不過目前Postman
不允許直接在指令碼中修改請求,所以我們只能使用預製簽名頭並使用全域性變數賦值的方式完成簽名頭的新增,我們將需要簽名的頭都預製在Postman的請求Header中,可以通過Bulk Edit
模式實現新增,Bulk Edit
請參照下圖進行切換
切換為Bulk Edit
模式後,可以將如下字串複製貼上到輸入框當中,被{{}}
括住的就是Postman的全域性變數,我們在指令碼中實現替換。Form內容的可以不新增Content-MD5頭
Date:{{Date}}
Content-MD5:{{Md5}}
X-Ca-Nonce:{{Nonce}}
X-Ca-Key:{{AppKey}}
X-Ca-Signature:{{Signature}}
X-Ca-SignatureMethod:HmacSHA356
X-Ca-Signature-Headers:{{SignatureHeaders}}
貼上後效果如圖
3.2. 使用Pre-request Script
指令碼實現簽名功能
點選紅圈圈住的位置,可以輸入Pre-request Script
,請複製貼上下面提供的程式碼到文字框當中
var appKey = "<YOUR APP KEY>";
var appSecret = "<YOUR APP SECRET>";
var md5 = calcMd5();
var date = new Date().toString();
var nonce = createUuid();
var textToSign = "";
textToSign += request.method + "
";
textToSign += request.headers["accept"] + "
";
textToSign += md5 + "
";
textToSign += request.headers["content-type"] + "
";
textToSign += date + "
";
var headers = headersToSign();
var signatureHeaders;
var sortedKeys = Array.from(headers.keys()).sort()
for (var headerName of sortedKeys) {
textToSign += headerName + ":" + headers.get(headerName) + "
";
signatureHeaders = signatureHeaders ? signatureHeaders + "," + headerName : headerName;
}
textToSign += urlToSign();
console.log("textToSign
" + textToSign.replace(/
/g, "#"));
var hash = CryptoJS.HmacSHA256(textToSign, appSecret)
console.log("hash:" + hash)
var signature = hash.toString(CryptoJS.enc.Base64)
console.log("signature:" + signature)
pm.globals.set(`AppKey`, appKey);
pm.globals.set(`Md5`, md5);
pm.globals.set("Date", date);
pm.globals.set("Signature", signature);
pm.globals.set("SignatureHeaders", signatureHeaders);
pm.globals.set("Nonce", nonce);
function headersToSign() {
var headers = new Map();
for (var name in request.headers) {
name = name.toLowerCase();
if (!name.startsWith(`x-ca-`)) {
continue;
}
if (name === "x-ca-signature" || name === "x-ca-signature-headers" || name == "x-ca-key" || name === `x-ca-nonce`) {
continue;
}
var value = request.headers[name];
headers.set(name, value);
}
headers.set(`x-ca-key`, appKey);
headers.set(`x-ca-nonce`, nonce);
return headers;
}
function urlToSign() {
var params = new Map();
var contentType = request.headers["content-type"];
if (contentType && contentType.startsWith(`application/x-www-form-urlencoded`)) {
const formParams = request.data.split("&");
formParams.forEach((p) => {
const ss = p.split(`=`);
params.set(ss[0], ss[1]);
})
}
const ss = request.url.split(`?`);
if (ss.length > 1 && ss[1]) {
const queryParams = ss[1].split(`&`);
queryParams.forEach((p) => {
const ss = p.split(`=`);
params.set(ss[0], ss[1]);
})
}
var sortedKeys = Array.from(params.keys())
sortedKeys.sort();
var l1 = ss[0].lastIndexOf(`/`);
var url = ss[0].substring(l1);
var first = true;
var qs
for (var k of sortedKeys) {
var s = k + "=" + params.get(k);
qs = qs ? qs + "&" + s : s;
console.log("key=" + k + " value=" + params.get(k));
}
return qs ? url + "?" + qs : url;
}
function calcMd5() {
var contentType = request.headers["content-type"];
if (request.data && !contentType.startsWith(`application/x-www-form-urlencoded`)) {
var data = request.data;
var md5 = CryptoJS.MD5(data);
var md5String = md5.toString(CryptoJS.enc.Base64);
console.log("data:" + data + "
md5:" + md5String);
return md5String;
} else {
return "";
}
}
function createUuid() {
return `xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx`.replace(/[xy]/g, function(c) {
var r = Math.random()*16|0, v = c == `x` ? r : (r&0x3|0x8);
return v.toString(16);
});
}
接下來我們就可以實現API閘道器的除錯了
相關文章
- Ocelot API閘道器的實現剖析API
- 30分鐘通過Kong實現.NET閘道器
- Spring Cloud Zuul API服務閘道器之請求路由SpringCloudZuulAPI路由
- 在Spring Boot中實現API閘道器與路由Spring BootAPI路由
- 開放API閘道器實踐(一) ——設計一個API閘道器API
- http請求到達後端的執行過程——閘道器篇HTTP後端
- API 閘道器 KongAPI
- Oracle 通過透明閘道器訪問mysqlOracleMySql
- Postman除錯技巧之介面簽名Postman除錯
- oracle通過透明閘道器連線mysql的配置OracleMySql
- API閘道器,企業級閘道器可擴充套件API套件
- 利用Spring Boot實現微服務的API閘道器統一限流與熔斷Spring Boot微服務API
- 開放API閘道器實踐(三) —— 限流API
- 微服務實踐分享(2)api閘道器微服務API
- 百億流量微服務閘道器的設計與實現微服務
- 通過 Passport 實現 API 請求認證(移動端的密碼授權令牌)PassportAPI密碼
- 高效能API閘道器(1)、微服務API閘道器架構設計API微服務架構
- 微服務技術棧:API閘道器中心,落地實現方案微服務API
- API 閘道器策略二三事API
- postman發請求前實現的操作Pre-request ScriptPostman
- 註冊中心與API閘道器不是這樣用的!API
- 得物自研API閘道器實踐之路API
- 【杭州活動】API 閘道器與高效能服務最佳實踐API
- 複製瀏覽器請求到Postman瀏覽器Postman
- PLC透過Profinet轉Modbus閘道器與流量計通訊案例
- postman除錯Postman除錯
- ORACLE通過透明閘道器連線DB2OracleDB2
- API閘道器:Apache APISIX 3.0與Kong 3.0比較APIApache
- 無線閘道器裝置使用和除錯方法(轉)除錯
- 北京Profinet轉Modbus閘道器配置除錯詳解除錯
- SpringCloud微服務專案實戰 - API閘道器Gateway詳解實現SpringGCCloud微服務APIGateway
- PLC雲閘道器助力非標自動化裝置實現遠端除錯運維除錯運維
- 服務閘道器過濾器過濾器
- Ocelot閘道器+IdentityServer4實現API許可權認證IDEServerAPI
- 智慧儀表透過Modbus轉Profinet閘道器與PLC通訊方案
- 【Azure 環境】請求經過應用程式閘道器,當響應內容大時遇見504超時報錯
- Oracle 通過透明閘道器訪問mysql配置步驟OracleMySql
- 利用Spring Boot實現微服務的API閘道器統一日誌Spring Boot微服務API