我想了解如何使用.NET Framework验证JWT令牌的签名。我正在使用在https://jwt.io/找到的令牌。C#如何验证JWT令牌上的签名?
如果我明白这应该如何工作,我可以使用HMACSHA256哈希算法与前两个令牌和一个秘密值来获取令牌的最后部分。如果匹配,那么签名是有效的。
在https://jwt.io/页显示计算散列以下述方式的例子:
HMACSHA256(
base64UrlEncode(header) + "." +
base64UrlEncode(payload), secret
)
不幸的是在.NET Framework的HMACSHA256对象没有这样的方法。您必须传入一个字节[]或流。也不存在任何秘密。但是,有一个构造函数将字节[]作为键。为了解决这个问题,我一直在将“secret”这个词转换成一个byte []来实例化HMACSHA256对象。
然后,我将base64编码的header.payload字符串转换为byte [],并将其传递给HMACSHA256
对象的ComputeHash
方法。
这里是我遇到问题的地方。 ComputeHash
的输出是一个字节数组。无论我如何尝试将此字节[]转换回字符串,它都不会匹配签名。我不明白我出错的地方。令牌的签名部分是散列值还是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[]