helper_20220215085858.js
3.17 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
'use strict';
const moment = require('moment');
module.exports = {
/**
* 对象拼接为字符串
* @param {object} object 待拼接的hash对象
*/
concatHash(object) {
const keys = Object.keys(object).sort();
let paramsStr = '';
for (let index = 0; index < keys.length; index++) {
const key = keys[index];
let value = object[key];
// object参数类型转换为string
if (typeof (value) === 'object') {
value = JSON.stringify(value);
}
paramsStr = paramsStr + `${key}${value}`;
}
return paramsStr;
},
err({ ctx, code, err, status }) {
ctx.body = {
success: false,
code: code || 1,
err,
};
ctx.status = status || 200;
},
// 优化错误信息可读性
errorReadable(e) {
switch (e.code) {
case 'invalid_param': { // 参数错误
const errorHash = {
missing_field: '缺失',
};
let msg = '';
for (let i = 0; i < e.errors.length; i++) {
msg += '参数' + e.errors[i].field + ' ' + (errorHash[e.errors[i].code] || e.errors[i].message) + ';';
}
return msg;
}
default:
console.log('未优化类型错误!');
return JSON.stringify(e);
}
},
success({ ctx, data, status }) {
ctx.body = {
success: true,
code: 0,
data,
};
ctx.status = status || 200;
},
async verifySign(ctx) {
const authorization = ctx.request.headers.authorization;
const timestamp = ctx.request.headers.timestamp;
const publicKey = ctx.request.headers.publickey;
if (!timestamp) {
this.err({
ctx,
err: 'hearder: timestamp不能为空',
});
return false;
}
if (!authorization) {
this.err({
ctx,
err: 'hearder: authorization不能为空',
});
return false;
}
if (!publicKey) {
this.err({
ctx,
err: 'hearder: publicKey不能为空',
});
return false;
}
// 验证时间不大于5秒
const time = moment().valueOf();
if (Math.abs(Number(timestamp) - time) > (ctx.app.config.timeEquation || 5000)) {
ctx.body = {
code: 1,
err: '签名超时',
};
return false;
}
// 验证签名
// 1. 获取请求者公钥
const platformKey = await ctx.model.PlatformKey.findOne({ where: { publicKey } });
if (!platformKey) {
ctx.body = {
code: 1,
err: 'publicKey不存在',
};
return false;
}
if (!platformKey.usable) {
ctx.body = {
code: 1,
err: '密钥对不可用',
};
return;
}
// 2. 对签名进行验证
// 2.1 合并参数并排序组合拼接
const allParams = { ...ctx.params, ...ctx.request.query, ...ctx.request.body, timestamp };
const paramsStr = this.concatHash(allParams);
const verify = this.service.sdk.gm.sm2VerifySign(paramsStr, authorization, publicKey);
// 3. 比对时间戳
if (!verify) {
ctx.body = {
code: 1,
err: '签名无效',
};
return false;
}
// 记录当前媒体平台
ctx.platformId = platformKey.platformId;
return true;
},
};