# 背景
Http 协议是无状态的。
任何的请求都是可以伪造的。
所以在 API 接口设计的时候 就需要判断调用方是否是我们信任的系统。
# 实现
一般前端具有 appId appSecret
前端加密步骤
- 参数中添加 时间戳 yyyy-MM-dd HH:mm:ss
- JSON Key 排序
- sign = MD5(JSON.stringify(jsonStr + appSecret))
- json.sign = sign.toUpperCase();
- aes 加密
参考代码
__encodeAesString(data, key) {
key = CryptoJS.enc.Utf8.parse(key);
data = CryptoJS.enc.Utf8.parse(data);
const encrypted = CryptoJS.AES.encrypt(data, key, {
mode: CryptoJS.mode.ECB,
padding: CryptoJS.pad.Pkcs7,
});
// 返回的是base64格式的密文
return encrypted.toString();
}
__keySort(json) {
const sortedKeys = Object.keys(json)
.filter(f => ![null, undefined].some(s => s === json[f]))
.sort();
return sortedKeys.reduce((acc, key) => {
if (json[key] && Array.isArray(json[key])) {
acc[key] = json[key];
return acc;
}
if (json[key] && typeof json[key] === 'object') {
acc[key] = this.__keySort(json[key]);
} else {
acc[key] = json[key];
}
return acc;
}, {});
}
__signStr(params) {
params.timestamp = format(new Date(), 'yyyy-MM-dd HH:mm:ss');
// sha1
let signStr = JSON.stringify(this.__keySort(params));
signStr = md5(
signStr +
this.appSecret
);
params.sign = signStr.toUpperCase();
// aes
const queryStr = this.__encodeAesString(
JSON.stringify(this.__keySort(params)),
this.appKey
);
return queryStr;
}