2016-08-02 64 views
2

我想了解如何使用.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[] 

回答

0

是令牌的签名部分的哈希值或base64编码 哈希值?

这是一个Base64 Url编码散列值。您需要对计算出的散列值进行编码以验证相等性。

查看以下单元测试以查看您的验证错误。

[TestClass] 
public class JwtUnitTest { 
    [TestMethod] 
    public void VerifySignature() { 

     string jwt = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9.TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ"; 
     string[] parts = jwt.Split(".".ToCharArray()); 
     var header = parts[0]; 
     var payload = parts[1]; 
     var signature = parts[2];//Base64UrlEncoded signature from the token 

     byte[] bytesToSign = getBytes(string.Join(".", header, payload)); 

     byte[] secret = getBytes("secret"); 

     var alg = new HMACSHA256(secret); 
     var hash = alg.ComputeHash(bytesToSign); 

     var computedSignature = Base64UrlEncode(hash); 

     Assert.AreEqual(signature, computedSignature); 
    } 

    private static byte[] getBytes(string value) { 
     return Encoding.UTF8.GetBytes(value); 
    } 

    // from JWT spec 
    private static string Base64UrlEncode(byte[] input) { 
     var output = Convert.ToBase64String(input); 
     output = output.Split('=')[0]; // Remove any trailing '='s 
     output = output.Replace('+', '-'); // 62nd char of encoding 
     output = output.Replace('/', '_'); // 63rd char of encoding 
     return output; 
    } 
} 
相关问题