|
|
@@ -454,40 +454,13 @@ export class MiniappChannelHandler implements ChannelHandler {
|
|
|
* @returns 验证结果
|
|
|
*/
|
|
|
private verifySignatureAlgorithm2(data: any, config: ChannelConfig): boolean {
|
|
|
- try {
|
|
|
- const { openId, time, gameid, serverid, playerName, sign } = data;
|
|
|
-
|
|
|
- // 构建待签名字符串 - 按字母顺序排序
|
|
|
- const params: any = {
|
|
|
- openId: openId.toString(),
|
|
|
- time: time.toString(),
|
|
|
- gameid: gameid.toString(),
|
|
|
- serverid: serverid.toString(),
|
|
|
- playerName: playerName.toString()
|
|
|
- };
|
|
|
-
|
|
|
- // 按字母顺序排序并拼接
|
|
|
- const sortedKeys = Object.keys(params).sort();
|
|
|
- const queryString = sortedKeys.map(key => `${key}=${params[key]}`).join('&');
|
|
|
-
|
|
|
- // 添加统计API密钥
|
|
|
- const stringToSign = `${queryString}&key=${config.loginConfig?.statApiKey}`;
|
|
|
-
|
|
|
- // 计算MD5签名
|
|
|
- const expectedSignature = CryptoJS.MD5(stringToSign).toString().toUpperCase();
|
|
|
-
|
|
|
- logger.info("签名算法2验证详情:", {
|
|
|
- queryString,
|
|
|
- stringToSign,
|
|
|
- expectedSignature,
|
|
|
- receivedSignature: sign
|
|
|
- });
|
|
|
-
|
|
|
- return sign === expectedSignature;
|
|
|
- } catch (error) {
|
|
|
- logger.error("签名算法2验证出错:", error);
|
|
|
- return false;
|
|
|
- }
|
|
|
+ return this.verifyCommonSignature(
|
|
|
+ data,
|
|
|
+ config.loginConfig?.statApiKey || '',
|
|
|
+ 'sign',
|
|
|
+ ['sign'],
|
|
|
+ false // 角色信息签名不需要URL编码
|
|
|
+ );
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
@@ -498,28 +471,12 @@ export class MiniappChannelHandler implements ChannelHandler {
|
|
|
*/
|
|
|
generateRoleInfoSignature(params: any, config: ChannelConfig): string | null {
|
|
|
try {
|
|
|
- const { openId, time, gameid, serverid, playerName } = params;
|
|
|
-
|
|
|
- // 构建待签名字符串 - 按字母顺序排序
|
|
|
- const signParams: any = {
|
|
|
- openId: openId.toString(),
|
|
|
- time: time.toString(),
|
|
|
- gameid: gameid.toString(),
|
|
|
- serverid: serverid.toString(),
|
|
|
- playerName: playerName.toString()
|
|
|
- };
|
|
|
-
|
|
|
- // 按字母顺序排序并拼接
|
|
|
- const sortedKeys = Object.keys(signParams).sort();
|
|
|
- const queryString = sortedKeys.map(key => `${key}=${signParams[key]}`).join('&');
|
|
|
-
|
|
|
- // 添加统计API密钥
|
|
|
- const stringToSign = `${queryString}&key=${config.loginConfig?.statApiKey}`;
|
|
|
-
|
|
|
- // 计算MD5签名
|
|
|
- const signature = CryptoJS.MD5(stringToSign).toString().toUpperCase();
|
|
|
-
|
|
|
- return signature;
|
|
|
+ return this.generateCommonSignature(
|
|
|
+ params,
|
|
|
+ config.loginConfig?.statApiKey || '',
|
|
|
+ ['sign'],
|
|
|
+ false // 角色信息签名不需要URL编码
|
|
|
+ );
|
|
|
} catch (error) {
|
|
|
logger.error("生成角色信息修改签名出错:", error);
|
|
|
return null;
|
|
|
@@ -533,46 +490,13 @@ export class MiniappChannelHandler implements ChannelHandler {
|
|
|
* @returns 验证结果
|
|
|
*/
|
|
|
private verifySignatureAlgorithm1(data: any, config: ChannelConfig): boolean {
|
|
|
- try {
|
|
|
- const { uid, gameid, timestamp, nonce, scene, content, nickname, title, usersign, signature } = data;
|
|
|
-
|
|
|
- // 构建待签名字符串 - 按字母顺序排序
|
|
|
- const params: any = {
|
|
|
- uid: uid.toString(),
|
|
|
- gameid: gameid.toString(),
|
|
|
- timestamp: timestamp.toString(),
|
|
|
- nonce: nonce.toString(),
|
|
|
- scene: scene.toString(),
|
|
|
- content: content
|
|
|
- };
|
|
|
-
|
|
|
- // 添加可选参数(如果存在)
|
|
|
- if (nickname) params.nickname = nickname;
|
|
|
- if (title) params.title = title;
|
|
|
- if (usersign) params.usersign = usersign;
|
|
|
-
|
|
|
- // 按字母顺序排序并拼接
|
|
|
- const sortedKeys = Object.keys(params).sort();
|
|
|
- const queryString = sortedKeys.map(key => `${key}=${params[key]}`).join('&');
|
|
|
-
|
|
|
- // 添加API密钥
|
|
|
- const stringToSign = `${queryString}&key=${config.loginConfig?.apiKey}`;
|
|
|
-
|
|
|
- // 计算MD5签名
|
|
|
- const expectedSignature = CryptoJS.MD5(stringToSign).toString().toUpperCase();
|
|
|
-
|
|
|
- logger.info("签名验证详情:", {
|
|
|
- queryString,
|
|
|
- stringToSign,
|
|
|
- expectedSignature,
|
|
|
- receivedSignature: signature
|
|
|
- });
|
|
|
-
|
|
|
- return signature === expectedSignature;
|
|
|
- } catch (error) {
|
|
|
- logger.error("签名算法1验证出错:", error);
|
|
|
- return false;
|
|
|
- }
|
|
|
+ return this.verifyCommonSignature(
|
|
|
+ data,
|
|
|
+ config.loginConfig?.apiKey || '',
|
|
|
+ 'signature',
|
|
|
+ ['signature'],
|
|
|
+ false // 内容安全签名不需要URL编码
|
|
|
+ );
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
@@ -583,34 +507,12 @@ export class MiniappChannelHandler implements ChannelHandler {
|
|
|
*/
|
|
|
generateContentSecuritySignature(params: any, config: ChannelConfig): string | null {
|
|
|
try {
|
|
|
- const { uid, gameid, timestamp, nonce, scene, content, nickname, title, usersign } = params;
|
|
|
-
|
|
|
- // 构建待签名字符串 - 按字母顺序排序
|
|
|
- const signParams: any = {
|
|
|
- uid: uid.toString(),
|
|
|
- gameid: gameid.toString(),
|
|
|
- timestamp: timestamp.toString(),
|
|
|
- nonce: nonce.toString(),
|
|
|
- scene: scene.toString(),
|
|
|
- content: content
|
|
|
- };
|
|
|
-
|
|
|
- // 添加可选参数(如果存在)
|
|
|
- if (nickname) signParams.nickname = nickname;
|
|
|
- if (title) signParams.title = title;
|
|
|
- if (usersign) signParams.usersign = usersign;
|
|
|
-
|
|
|
- // 按字母顺序排序并拼接
|
|
|
- const sortedKeys = Object.keys(signParams).sort();
|
|
|
- const queryString = sortedKeys.map(key => `${key}=${signParams[key]}`).join('&');
|
|
|
-
|
|
|
- // 添加API密钥
|
|
|
- const stringToSign = `${queryString}&key=${config.loginConfig?.apiKey}`;
|
|
|
-
|
|
|
- // 计算MD5签名
|
|
|
- const signature = CryptoJS.MD5(stringToSign).toString().toUpperCase();
|
|
|
-
|
|
|
- return signature;
|
|
|
+ return this.generateCommonSignature(
|
|
|
+ params,
|
|
|
+ config.loginConfig?.apiKey || '',
|
|
|
+ ['signature'],
|
|
|
+ false // 内容安全签名不需要URL编码
|
|
|
+ );
|
|
|
} catch (error) {
|
|
|
logger.error("生成内容安全签名出错:", error);
|
|
|
return null;
|
|
|
@@ -687,39 +589,109 @@ export class MiniappChannelHandler implements ChannelHandler {
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
- * 小程序签名函数(签名算法3)
|
|
|
+ * 通用签名生成函数
|
|
|
+ * @param params 参数对象
|
|
|
+ * @param privateKey 私钥
|
|
|
+ * @param excludeKeys 需要排除的键(如sign)
|
|
|
+ * @param needUrlEncode 是否需要URL编码
|
|
|
+ * @returns 签名结果
|
|
|
+ */
|
|
|
+ public generateCommonSignature(
|
|
|
+ params: any,
|
|
|
+ privateKey: string,
|
|
|
+ excludeKeys: string[] = ['sign'],
|
|
|
+ needUrlEncode: boolean = true
|
|
|
+ ): string {
|
|
|
+ try {
|
|
|
+ // 1. 过滤掉空值和排除的键
|
|
|
+ const filteredParams: any = {};
|
|
|
+ Object.keys(params).forEach(key => {
|
|
|
+ if (!excludeKeys.includes(key) && params[key] !== null && params[key] !== undefined && params[key] !== '') {
|
|
|
+ filteredParams[key] = params[key].toString();
|
|
|
+ }
|
|
|
+ });
|
|
|
+
|
|
|
+ // 2. 按字母顺序排序并构建查询字符串
|
|
|
+ const sortedKeys = Object.keys(filteredParams).sort();
|
|
|
+ const queryString = sortedKeys.map(key => {
|
|
|
+ const value = filteredParams[key];
|
|
|
+ const encodedValue = needUrlEncode ? encodeURIComponent(value) : value;
|
|
|
+ return `${key}=${encodedValue}`;
|
|
|
+ }).join('&');
|
|
|
+
|
|
|
+ // 3. 拼接私钥
|
|
|
+ const stringToSign = `${queryString}&key=${privateKey}`;
|
|
|
+
|
|
|
+ // 4. 计算MD5并转大写
|
|
|
+ const signature = CryptoJS.MD5(stringToSign).toString().toUpperCase();
|
|
|
+
|
|
|
+ logger.info("通用签名生成详情:", {
|
|
|
+ filteredParams,
|
|
|
+ queryString,
|
|
|
+ stringToSign,
|
|
|
+ signature
|
|
|
+ });
|
|
|
+
|
|
|
+ return signature;
|
|
|
+ } catch (error) {
|
|
|
+ logger.error("通用签名生成出错:", error);
|
|
|
+ return '';
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 小程序签名函数(签名算法3)- 兼容旧接口
|
|
|
* @param parameters 参数数组
|
|
|
* @param privateKey 私钥
|
|
|
* @returns 签名结果
|
|
|
*/
|
|
|
private generateSignature(parameters: string[], privateKey: string): string {
|
|
|
- // 1. 过滤掉空值和sign参数
|
|
|
- const filteredParams = parameters.filter(param => {
|
|
|
- const [key, value] = param.split('=');
|
|
|
- return key !== 'sign' && value && value.trim() !== '';
|
|
|
- });
|
|
|
-
|
|
|
- // 2. 对参数进行URL编码
|
|
|
- const encodedParams = filteredParams.map(param => {
|
|
|
+ // 将参数数组转换为对象
|
|
|
+ const params: any = {};
|
|
|
+ parameters.forEach(param => {
|
|
|
const [key, value] = param.split('=');
|
|
|
- const encodedValue = encodeURIComponent(value);
|
|
|
- return `${key}=${encodedValue}`;
|
|
|
- });
|
|
|
-
|
|
|
- // 3. 按字母顺序排序
|
|
|
- encodedParams.sort((a, b) => {
|
|
|
- return a.localeCompare(b);
|
|
|
+ if (key && value) {
|
|
|
+ params[key] = value;
|
|
|
+ }
|
|
|
});
|
|
|
|
|
|
- // 4. 用&连接所有参数
|
|
|
- const queryString = encodedParams.join('&');
|
|
|
+ return this.generateCommonSignature(params, privateKey, ['sign'], true);
|
|
|
+ }
|
|
|
|
|
|
- // 5. 拼接私钥
|
|
|
- const stringToSign = `${queryString}&key=${privateKey}`;
|
|
|
+ /**
|
|
|
+ * 通用签名验证函数
|
|
|
+ * @param data 请求数据
|
|
|
+ * @param privateKey 私钥
|
|
|
+ * @param signKey 签名字段名
|
|
|
+ * @param excludeKeys 需要排除的键
|
|
|
+ * @param needUrlEncode 是否需要URL编码
|
|
|
+ * @returns 验证结果
|
|
|
+ */
|
|
|
+ private verifyCommonSignature(
|
|
|
+ data: any,
|
|
|
+ privateKey: string,
|
|
|
+ signKey: string = 'sign',
|
|
|
+ excludeKeys: string[] = ['sign'],
|
|
|
+ needUrlEncode: boolean = true
|
|
|
+ ): boolean {
|
|
|
+ try {
|
|
|
+ const receivedSignature = data[signKey];
|
|
|
+ if (!receivedSignature) {
|
|
|
+ return false;
|
|
|
+ }
|
|
|
|
|
|
- // 6. 计算MD5并转大写
|
|
|
- const signature = CryptoJS.MD5(stringToSign).toString().toUpperCase();
|
|
|
+ const expectedSignature = this.generateCommonSignature(data, privateKey, excludeKeys, needUrlEncode);
|
|
|
+
|
|
|
+ logger.info("通用签名验证详情:", {
|
|
|
+ receivedSignature,
|
|
|
+ expectedSignature,
|
|
|
+ isValid: receivedSignature === expectedSignature
|
|
|
+ });
|
|
|
|
|
|
- return signature;
|
|
|
- }
|
|
|
+ return receivedSignature === expectedSignature;
|
|
|
+ } catch (error) {
|
|
|
+ logger.error("通用签名验证出错:", error);
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ }
|
|
|
}
|