后端接口为了安全考虑, 通常会增加接口参数签名认证;增加接口参数签名认证, postman直接调用,会认证失败, 需要实现一套和前端项目一样的签名动作;
api参数签名认证api参数签名认证原理
- api-time: 本次API调用的有效时间,超过该时间调用失效,避免重放攻击
- api-key: 与api-secret是一个pair对,一一对应,知道了api-key即可查询到api-secret
- api-signature: api-secret和message一起生成的签名,这里的message一般包括api-key, 请求方法, get, post参数
api-signature的生成规则一般为: crypto-js的hmac_sha256,输出值需转化为base64字符串
postman pre-request签名计算
var apiKey = pm.globals.get("apiKey");
var apiSecret = pm.globals.get("apiSecret");
const query = pm.request.url.query;
var keys = [];
var map = {};
query?.each(e => {
let disabled = e["disabled"];
if (!disabled) {
let k = e["key"];
keys.push(k);
map[k] = e["value"];
}
});
const queryArr = [];
keys.sort();
keys.forEach(k => {
queryArr.push(k + "=" + map[k]);
});
const queryStr = queryArr.join("&");
const body = JSON.stringify(JSON.parse(pm.request.body.raw.toString()));
var method = request.method;
var signArr = [apiKey, method.toLowerCase(), queryStr, body];
const signSrcStr = signArr.join('&');
console.log(signSrcStr);
var signatureBase64 = CryptoJS.HmacSHA256(signSrcStr, apiSecret).toString(CryptoJS.enc.Base64);
console.log("signatureBase64", signatureBase64);
pm.environment.set("api-signature", signatureBase64);
const timeStr = Math.round(new Date().getTime());
pm.environment.set("api-time", timeStr);
pm.request.body = body;
java后端签名计算
class ApiPreHandler {
public static String generateHmac256(String msg, String key) {
if (Objects.isNull(msg)) {
return "";
}
if (Objects.isNull(key)) {
return msg;
}
final String algorithm = "HmacSHA256";
try {
SecretKeySpec secretKeySpec = new SecretKeySpec(key.getBytes(StandardCharsets.UTF_8), algorithm);
Mac mac = Mac.getInstance(algorithm);
mac.init(secretKeySpec);
byte[] bytes = mac.doFinal(msg.getBytes());
return Base64.getEncoder().encodeToString(bytes);
} catch (Exception e) {
LogUtils.error(e.getMessage(), e);
return "";
}
}
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
String requestURI = request.getRequestURI();
String method = request.getMethod().toLowerCase(Locale.ROOT);
String querySorted = getSortedQuery(request.getQueryString());
String body = request.getReader().lines().collect(Collectors.joining());
String apiSignature = request.getHeader("api-signature");
String signStrSrc = String.join("&", Lists.newArrayList(apiKey, method, querySorted, body));
log.info("requestURI: {}, singStrSrc={}", requestURI, signStrSrc);
String calcSign = SecurityUtils.generateHmac256(signStrSrc, apiSecret);
if (!Objects.equals(apiSignature, calcSign)) {
log.error("api-signature denied, signStrSrc={}", signStrSrc);
return false;
}
return true;
}
}