Node.js 端的接口签名处理

用MD5,SHA256,HMAC-SHA256,RSA-SHA256签名算法
适用场景
博客或网站接口:保护评论提交,数据查询等接口,防止恶意请求或数据篡改
前后端分离项目:确保前端发送的请求未被中间人篡改,验证请求来源合法性
服务间调用:用于微服务,第三方API交互,通过签名确认调用方身份
爬虫攻防:作为反爬策略的一部分,只有正确生成签名的请求才能访问接口
const crypto = require('crypto');
const fs = require('fs');
class ApiSignature {
constructor(config = {}) {
this.appId = config.appId || 'w7y_blog_api_20251123';
this.appSecret = config.appSecret || 'w7y_blog_secret_8f2d9a3e_20251123';
this.privateKey = config.privateKey || fs.readFileSync('private_key.pem', 'utf8');
this.algo = config.algo || 'sha256';
}
generateNonce(length = 16) {
return crypto.randomBytes(length).toString('hex');
}
generateTimestamp() {
return Math.floor(Date.now() / 1000);
}
md5Sign(data, key = '') {
const signStr = data + key;
return crypto.createHash('md5').update(signStr, 'utf8').digest('hex');
}
sha256Sign(data, key = '') {
const signStr = data + key;
return crypto.createHash('sha256').update(signStr, 'utf8').digest('hex');
}
hmacSha256Sign(data, key) {
return crypto.createHmac('sha256', key).update(data, 'utf8').digest('hex');
}
hmacMd5Sign(data, key) {
return crypto.createHmac('md5', key).update(data, 'utf8').digest('hex');
}
rsaSha256Sign(data, privateKey) {
const sign = crypto.createSign('RSA-SHA256');
sign.update(data);
sign.end();
return sign.sign(privateKey, 'base64');
}
buildSignString(params) {
const sortedKeys = Object.keys(params).sort();
const pairs = [];

    for (const key of sortedKeys) {
        const value = params[key];
        if (value !== null && value !== undefined && value !== '') {
            pairs.push(`${key}=${value}`);
        }
    }

    return pairs.join('&');
}
generateSignature(params, method = 'sha256', secret = this.appSecret) {
    const signString = this.buildSignString(params);

    switch (method.toLowerCase()) {
        case 'md5':
            return this.md5Sign(signString, secret);
        case 'sha256':
            return this.sha256Sign(signString, secret);
        case 'hmac_sha256':
            return this.hmacSha256Sign(signString, secret);
        case 'hmac_md5':
            return this.hmacMd5Sign(signString, secret);
        case 'rsa_sha256':
            return this.rsaSha256Sign(signString, this.privateKey);
        default:
            throw new Error(`Unsupported signature method: ${method}`);
    }
}
buildSignedParams(params = {}, options = {}) {
    const {
        method = 'sha256',
        includeAppId = true,
        includeTimestamp = true,
        includeNonce = true,
        secret = this.appSecret,
        version = '1.0'
    } = options;

    const signedParams = { ...params };

    // 添加应用ID
    if (includeAppId && this.appId) {
        signedParams.app_id = this.appId;
    }
    // 添加时间戳
    if (includeTimestamp) {
        signedParams.timestamp = this.generateTimestamp();
    }
    // 添加随机字符串
    if (includeNonce) {
        signedParams.nonce_str = this.generateNonce();
    }
    // 添加版本号
    signedParams.version = version;
    // 生成签名
    signedParams.sign = this.generateSignature(signedParams, method, secret);

    return signedParams;
}
verifySignature(params, receivedSign, method = 'sha256', secret = this.appSecret) {
    const calculatedSign = this.generateSignature(params, method, secret);
    return calculatedSign === receivedSign;
}
buildAuthorizationHeader(params = {}, method = 'sha256') {
    const signedParams = this.buildSignedParams(params, { method });
    const token = Buffer.from(JSON.stringify(signedParams)).toString('base64');
    return `Bearer ${token}`;
}
parseAuthorizationHeader(authHeader) {
    if (!authHeader.startsWith('Bearer ')) {
        return null;
    }
    try {
        const token = authHeader.substring(7);
        const decoded = Buffer.from(token, 'base64').toString('utf8');
        return JSON.parse(decoded);
    } catch (error) {
        return null;
    }
}

}
if (require.main === module) {
// 初始化签名器
const signature = new ApiSignature({
appId: 'your_app_id',
appSecret: 'your_app_secret',
privateKey: 'your_rsa_private_key'
});
console.log('\n=== 签名 ===');
const complexParams = {
name: '南黎w7y',
age: 20,
hobbies: ['阅读', '游泳', ' 音乐', ' 旅行', ' 看书', ' 打篮球'],
profile: {
city: '西安',
occupation: '程序员'
}
};
// 将复杂对象转为json字符串进行签名
const jsonParams = {};
for (const [key, value] of Object.entries(complexParams)) {
jsonParams[key] = JSON.stringify(value);
}
const signedParams3 = signature.buildSignedParams(jsonParams,
{
method: 'sha256'
});
console.log('签名:', signedParams3.sign);
}
module.exports = ApiSignature;

posted @ 2025-11-23 18:54  南黎w7y  阅读(3)  评论(0)    收藏  举报