C# 通过邮递员的HMAC身份验证

C# 通过邮递员的HMAC身份验证,c#,security,postman,hmac,C#,Security,Postman,Hmac,我正在使用一个为Web API项目设置HMAC身份验证的示例。此处提供了原始示例源代码/项目: 我试图让Postman在其预请求脚本中构造并发送get请求。然而,401申请总是失败,我不知道为什么。 邮递员预请求脚本: var AppId = "4d53bce03ec34c0a911182d4c228ee6c"; var APIKey = "A93reRTUJHsCuQSHR+L3GxqOJyDmQpCgps102ciuabc="; var requestURI = "http%3a%2f%2

我正在使用一个为Web API项目设置HMAC身份验证的示例。此处提供了原始示例源代码/项目:

我试图让Postman在其预请求脚本中构造并发送get请求。然而,401申请总是失败,我不知道为什么。
邮递员预请求脚本:

var AppId = "4d53bce03ec34c0a911182d4c228ee6c";
var APIKey = "A93reRTUJHsCuQSHR+L3GxqOJyDmQpCgps102ciuabc=";
var requestURI = "http%3a%2f%2flocalhost%3a55441%2fapi%2fv1%2fdata";
var requestMethod = "GET";
var requestTimeStamp = "{{$timestamp}}";
var nonce = "1";
var requestContentBase64String = "";

var signatureRawData  = AppId + requestMethod + requestURI + requestTimeStamp +  nonce + requestContentBase64String; //check
var signature = CryptoJS.enc.Utf8.parse(signatureRawData);
var secretByteArray = CryptoJS.enc.Base64.parse(APIKey);
var signatureBytes = CryptoJS.HmacSHA256(signature,secretByteArray)

var requestSignatureBase64String = CryptoJS.enc.Base64.stringify(signatureBytes);
postman.setGlobalVariable("key", "amx " + AppId + ":" + requestSignatureBase64String + ":" + nonce + ":" + requestTimeStamp);

经过几天的测试,我发现了这个问题。实际上,这与邮递员提供的变量占位符有关。在测试占位符{{$timestamp}时,其面值传递了一个有效值。当我将签名剥离回来,只使用一个片段开始时,我成功地获得了身份验证。直到我把时间戳占位符放回去


当我将占位符替换为在标题中传递的实际值时,效果很好。我只能得出结论,一定有一些我看不到的额外角色。也许在邮递员那一边,当它创建签名的时候。问题扩展到其他占位符,如{{$guid}

这是我在Pre脚本中使用的代码。它适用于任何查询GET、PUT、POST和DELETE

您需要更改AppId和APIKey值,并在最后一行调整环境变量“hmacKey”的名称

var uuid = require('uuid');
var moment = require("moment")

var AppId = "4d53bce03ec34c0a911182d4c228ee6c";
var APIKey = "A93reRTUJHsCuQSHR+L3GxqOJyDmQpCgps102ciuabc=";
var requestURI = encodeURIComponent(pm.environment.values.substitute(pm.request.url, null, false).getRaw()).toLowerCase();
var requestMethod = pm.request.method;
var requestTimeStamp = moment(new Date().toUTCString()).valueOf() / 1000;
var nonce = uuid.v4();
var requestContentBase64String = "";

if (pm.request.body) {
    var md5 = CryptoJS.MD5(pm.request.body.toString());
    requestContentBase64String = CryptoJS.enc.Base64.stringify(md5);
}

var signatureRawData  = AppId + requestMethod + requestURI + requestTimeStamp +  nonce + requestContentBase64String; //check
var signature = CryptoJS.enc.Utf8.parse(signatureRawData);
var secretByteArray = CryptoJS.enc.Base64.parse(APIKey);
var signatureBytes = CryptoJS.HmacSHA256(signature,secretByteArray);
var requestSignatureBase64String = CryptoJS.enc.Base64.stringify(signatureBytes);

var hmacKey = "amx " + AppId + ":" + requestSignatureBase64String + ":" + nonce + ":" + requestTimeStamp;
postman.setEnvironmentVariable("hmacKey", hmacKey);

好剧本!我确实在让它工作时遇到了一些麻烦,结果证明toLowerCase()应该在编码之前完成
var requestURI=encodeURIComponent(pm.environment.values.substitute(pm.request.url,null,false).getRaw().toLowerCase())
So在
encodeURIComponent(…)
中。我还遇到了一个问题,当url中没有明确包含协议时,客户端将从服务器获得不同的签名。例如,
localhost:5000/api/endpoint
我总是在我的URL中包含协议,我正在运行不同的环境,比如Prod、Pre-Prod、UAT、Dev和debug(带有端口号),它工作正常。也许我可以给你我的身份验证方法的.net实现,它是一个Nuget并且非常容易使用。还要确保邮递员和你的APINice之间的钥匙完全相同——这非常有用