简体   繁体   English

c#如何验证签名JWT?

[英]c# How to verify signature JWT?

I have a token, a file containing public key and I want to verify the signature.我有一个令牌,一个包含公钥的文件,我想验证签名。 I tried to verify signature based on this .我试图基于验证签名。

However, decodedCrypto and decodedSignature don't match.但是,decodedCrypto 和decodedSignature 不匹配。

Here is my code:这是我的代码:

public static string Decode(string token, string key, bool verify)
    {
        var parts = token.Split('.');
        var header = parts[0];
        var payload = parts[1];
        byte[] crypto = Base64UrlDecode(parts[2]);

        var headerJson = Encoding.UTF8.GetString(Base64UrlDecode(header));
        var headerData = JObject.Parse(headerJson);
        var payloadJson = Encoding.UTF8.GetString(Base64UrlDecode(payload));
        var payloadData = JObject.Parse(payloadJson);

        if (verify)
        {
            var bytesToSign = Encoding.UTF8.GetBytes(string.Concat(header, ".", payload));
            var keyBytes = Encoding.UTF8.GetBytes(key);
            var algorithm = (string)headerData["alg"];
            var signature = HashAlgorithms[GetHashAlgorithm(algorithm)](keyBytes, bytesToSign);
            var decodedCrypto = Convert.ToBase64String(crypto);
            var decodedSignature = Convert.ToBase64String(signature);

            if (decodedCrypto != decodedSignature)
            {
                throw new ApplicationException(string.Format("Invalid signature. Expected {0} got {1}", decodedCrypto, decodedSignature));
            }
        }

        return payloadData.ToString();
    }

I'm sure that the signature of token is valid.我确定令牌的签名是有效的。 I try to verify on https://jwt.io/ and it showed that Signature verified.我尝试在https://jwt.io/上进行验证,结果显示签名已验证。 So the problem is the algorithm to encode, decode.所以问题是编码、解码的算法。

Is there anyone can solve this problem?有没有人可以解决这个问题? The algorithm is RS256算法为 RS256

在此处输入图片说明

I finally got a solution from my colleague. 我终于得到了同事的解决方案。

For those who have the same problem, try my code: 对于那些有同样问题的人,请尝试我的代码:

public static string Decode(string token, string key, bool verify = true)
{
    string[] parts = token.Split('.');
    string header = parts[0];
    string payload = parts[1];
    byte[] crypto = Base64UrlDecode(parts[2]);

    string headerJson = Encoding.UTF8.GetString(Base64UrlDecode(header));
    JObject headerData = JObject.Parse(headerJson);

    string payloadJson = Encoding.UTF8.GetString(Base64UrlDecode(payload));
    JObject payloadData = JObject.Parse(payloadJson);

    if (verify)
    {
        var keyBytes = Convert.FromBase64String(key); // your key here

        AsymmetricKeyParameter asymmetricKeyParameter = PublicKeyFactory.CreateKey(keyBytes);
        RsaKeyParameters rsaKeyParameters = (RsaKeyParameters)asymmetricKeyParameter;
        RSAParameters rsaParameters = new RSAParameters();
        rsaParameters.Modulus = rsaKeyParameters.Modulus.ToByteArrayUnsigned();
        rsaParameters.Exponent = rsaKeyParameters.Exponent.ToByteArrayUnsigned();
        RSACryptoServiceProvider rsa = new RSACryptoServiceProvider();
        rsa.ImportParameters(rsaParameters);

        SHA256 sha256 = SHA256.Create();
        byte[] hash = sha256.ComputeHash(Encoding.UTF8.GetBytes(parts[0] + '.' + parts[1]));

        RSAPKCS1SignatureDeformatter rsaDeformatter = new RSAPKCS1SignatureDeformatter(rsa);
        rsaDeformatter.SetHashAlgorithm("SHA256");
        if (!rsaDeformatter.VerifySignature(hash, FromBase64Url(parts[2])))
            throw new ApplicationException(string.Format("Invalid signature"));
    }

    return payloadData.ToString();
}

It works for me. 这个对我有用。 The algorithm is RS256. 算法是RS256。

I know this is an old thread but I could have recommended you to use this library instead of writing on your own. 我知道这是一个旧线程但我可以recommended你使用这个库而不是自己编写。 It has got some good documentation to get started. 它有一些很好的文档来开始。 Am using it without any issues. 我没有任何问题使用它。

How about using JwtSecurityTokenHandler ? 如何使用JwtSecurityTokenHandler it could look something like this: 它可能看起来像这样:

public bool ValidateToken(string token, byte[] secret)
{
    var tokenHandler = new JwtSecurityTokenHandler();

    var validationParameters = new TokenValidationParameters
    {
        ValidateIssuerSigningKey = true,
        IssuerSigningToken = new BinarySecretSecurityToken(secret)
    };

    SecurityToken validatedToken;
    try
    {
        tokenHandler.ValidateToken(token, validationParameters, out validatedToken);
    }
    catch (Exception)
    {
       return false;
    }

    return validatedToken != null;
}

Be aware I haven't tested it but we used a similar implementation in one of the projects 请注意,我没有对其进行测试,但我们在其中一个项目中使用了类似的实现

byte[] crypto = Base64UrlDecode(parts[2]);

In this line you are base64 decoding signature part of JWT token, but as I know that part isn't base64 encoded. 在这一行中,你是base64解码JWT令牌的签名部分,但据我所知,该部分不是base64编码的。 Please try this code. 请试试这段代码。 ( I have commented out unnecessary lines ) (我已经注释掉了不必要的线条)

public static string Decode(string token, string key, bool verify)
{
    var parts = token.Split('.');
    var header = parts[0];
    var payload = parts[1];
    // byte[] crypto = Base64UrlDecode(parts[2]);
    var jwtSignature = parts[2];

    var headerJson = Encoding.UTF8.GetString(Base64UrlDecode(header));
    var headerData = JObject.Parse(headerJson);
    var payloadJson = Encoding.UTF8.GetString(Base64UrlDecode(payload));
    var payloadData = JObject.Parse(payloadJson);

    if (verify)
    {
        var bytesToSign = Encoding.UTF8.GetBytes(string.Concat(header, ".", payload));
        var keyBytes = Encoding.UTF8.GetBytes(key);
        var algorithm = (string)headerData["alg"];
        var computedJwtSignature = Encoding.UTF8.GetString(HashAlgorithms[GetHashAlgorithm(algorithm)](keyBytes, bytesToSign));
        // var decodedCrypto = Convert.ToBase64String(crypto);
        // var decodedSignature = Convert.ToBase64String(signature);

        if (jwtSignature != computedJwtSignature)
        {
            throw new ApplicationException(string.Format("Invalid signature. Expected {0} got {1}", decodedCrypto, decodedSignature));
        }
    }

    return payloadData.ToString();
}

有人可以和我分享一个类似的代码,用于在 C# 或 powershell 中生成令牌

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM