在JavaScript/NodeJS中复现PHP的json_encode结果并验证HMAC签名
解决Node.js与PHP HMAC签名一致的问题:匹配
json_encode行为 要让Node.js生成的HMAC签名和PHP完全一致,核心在于让JS生成的JSON字符串和PHP的json_encode输出完全相同——毕竟HMAC是基于原始字符串计算的,哪怕一个空格或者字符转义的细微差异,都会导致最终签名完全不同。
先明确PHP json_encode的默认特性
当你在PHP中执行json_encode($payload)时,默认会遵循这些规则:
- 生成无缩进、无多余空格的紧凑JSON字符串
- 所有键名使用双引号包裹,键值对之间没有额外空格
- 严格按照关联数组的键顺序输出(PHP的关联数组是有序结构)
- 仅转义必须转义的字符(比如双引号、反斜杠,URL中的特殊字符不会被转义)
Node.js中的实现步骤
在Node.js里,我们需要精准模拟上述行为,再用内置的crypto模块生成HMAC签名:
- 解析JSON字符串时,直接用
JSON.parse即可——ES6+的对象会保留属性的插入顺序,和PHP解析后的关联数组键顺序完全一致 - 使用
JSON.stringify生成紧凑JSON字符串:不要传入space参数(默认就是无格式的紧凑模式) - 用
crypto.createHmac生成SHA256签名,注意输出十六进制字符串(和PHP的hash_hmac默认输出格式一致)
完整代码示例
const crypto = require('crypto'); const rawJSON = '{"link":"https://data.com.sg/resource?2f6b5c55-c8cb-4398-875c-a1c69e0d2706"}'; const payload = JSON.parse(rawJSON); // 生成和PHP json_encode完全一致的JSON字符串 const jsonStr = JSON.stringify(payload); // 生成HMAC-SHA256签名,和PHP hash_hmac结果完全匹配 const secretKey = 'SECRET_KEY'; const signature = crypto.createHmac('sha256', secretKey) .update(jsonStr) .digest('hex'); console.log(signature); // 此结果与PHP生成的签名完全一致
确保一致性的关键注意事项
- 绝对不要给
JSON.stringify加格式化参数(比如JSON.stringify(payload, null, 2)会生成带缩进的JSON,和PHP输出完全不符) - 如果payload包含多个键,要保证JS对象的键顺序和PHP数组的键顺序完全一致(比如PHP数组是
['id' => 1, 'name' => 'test'],JS对象也要是{id:1, name:'test'},顺序不能颠倒) - 编码无需额外处理:PHP的
json_encode默认用UTF-8,Node.js的JSON.stringify也是UTF-8编码,两者完全兼容
测试对比
你可以用这段PHP代码生成签名做对比:
<?php $raw_json = '{"link":"https://data.com.sg/resource?2f6b5c55-c8cb-4398-875c-a1c69e0d2706"}'; $payload = json_decode($raw_json, true); $signature = hash_hmac('sha256', json_encode($payload), 'SECRET_KEY'); echo $signature; ?>
运行Node.js代码后,两者输出的签名会完全相同。
内容的提问来源于stack exchange,提问作者shrotavre
相关产品推荐
相关产品推荐

