我试图了解如何使用 .NET Framework 验证 JWT 令牌的签名。我正在使用在以下位置找到的令牌https://jwt.io/ https://jwt.io/ .
如果我理解这是如何工作的,我可以使用 HMACSHA256 哈希算法与前两个令牌和一个秘密值来获取令牌的最后一部分。如果匹配,则签名有效。
上的例子https://jwt.io/ https://jwt.io/页面显示按以下方式计算哈希:
HMACSHA256(
base64UrlEncode(header) + "." +
base64UrlEncode(payload), secret
)
不幸的是.NET Framework 中的HMACSHA256 对象没有这样的方法。您必须传入一个 byte[] 或一个流。秘密也是无可争议的。然而,有一个构造函数接受 byte[] 作为键。为了解决这个问题,我将“secret”一词转换为 byte[],并用它实例化 HMACSHA256 对象。
然后,我将 base64 编码的 header.payload 字符串转换为 byte[] 并将其传递给ComputeHash
的方法HMACSHA256
目的。
这是我遇到问题的地方。输出来自ComputeHash
是一个字节数组。无论我如何尝试将此 byte[] 转换回字符串,它都不会与签名匹配。我不明白我哪里错了。令牌的签名部分是哈希值还是 Base64 编码的哈希值?
这是我的代码:
string jwt = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9.TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ";
string[] parts = jwt.Split(".".ToCharArray());
string headerDotPayload = string.Format("{0}.{1}", parts[0], parts[1]);
string signature = parts[2];
byte[] secret = System.Text.UTF8Encoding.UTF8.GetBytes("secret");
byte[] input = System.Text.UTF8Encoding.UTF8.GetBytes(headerDotPayload);
var alg = new HMACSHA256(secret);
byte[] hash = alg.ComputeHash(input);
//Attempting to verify
StringBuilder result = new StringBuilder();
for (int i = 0; i < hash.Length; i++)
{
result.Append(hash[i].ToString("x2"));
}
string verify1 = result.ToString(); //Does not match signature
string verify2 = System.Text.UTF8Encoding.UTF8.GetString(hash); //Does not match signature
byte[] verify3 = System.Text.UTF8Encoding.UTF8.GetBytes(signature); //Does not match value in the hash byte[]