首页 文章

使用System.IdentityModel.Tokens.Jwt解码和验证JWT令牌

提问于
浏览
81

我一直在使用JWT库来解码Json Web Token,并希望切换到Microsoft的官方JWT实现,System.IdentityModel.Tokens.Jwt .

文档非常稀疏,所以我很难弄清楚如何完成我在JWT库中所做的工作 . 使用JWT库,有一个Decode方法,它采用base64编码的JWT并将其转换为JSON,然后可以对其进行反序列化 . 我想使用System.IdentityModel.Tokens.Jwt做类似的事情,但经过大量的挖掘,无法弄清楚如何 .

为了它的 Value ,我正在从cookie中读取JWT令牌,以便与Google的身份框架一起使用 .

任何帮助,将不胜感激 .

2 回答

  • 19

    在包中有一个名为 JwtSecurityTokenHandler 的类,它派生自 System.IdentityModel.Tokens.SecurityTokenHandler . 在WIF中,这是用于反序列化和序列化安全令牌的核心类 .

    该类有一个 ReadToken(String) 方法,它将采用base64编码的JWT字符串并返回表示JWT的 SecurityToken .

    SecurityTokenHandler 也有一个 ValidateToken(SecurityToken) 方法,它接收 SecurityToken 并创建 ReadOnlyCollection<ClaimsIdentity> . 通常对于JWT,这将包含一个 ClaimsIdentity 对象,该对象具有一组声明,表示原始JWT的属性 .

    JwtSecurityTokenHandlerValidateToken 定义了一些额外的重载,特别是它有 ClaimsPrincipal ValidateToken(JwtSecurityToken, TokenValidationParameters) 重载 . TokenValidationParameters 参数允许您指定令牌签名证书(作为 X509SecurityTokens 的列表) . 它还有一个重载,它将JWT作为 string 而不是 SecurityToken .

    执行此操作的代码相当复杂,但可以在名为"ADAL - Native App to REST service - Authentication with ACS via Browser Dialog"的开发人员示例中的Global.asax.cx代码( TokenValidationHandler 类)中找到,位于

    http://code.msdn.microsoft.com/AAL-Native-App-to-REST-de57f2cc

    或者, JwtSecurityToken 类具有不在基础 SecurityToken 类上的其他方法,例如 Claims 属性,无需通过 ClaimsIdentity 集合即可获取所包含的声明 . 它还有一个 Payload 属性,它返回一个 JwtPayload 对象,可以让你获得令牌的原始JSON . 这取决于您的场景哪种方法最合适 .

    SecurityTokenHandler 类的一般(即非JWT特定)文档位于

    http://msdn.microsoft.com/en-us/library/system.identitymodel.tokens.securitytokenhandler.aspx

    根据您的应用程序,您可以将JWT处理程序配置为WIF管道,就像任何其他处理程序一样 .

    其中有3个样品在不同类型的应用中使用

    http://code.msdn.microsoft.com/site/search?f%5B0%5D.Type=SearchText&f%5B0%5D.Value=aal&f%5B1%5D.Type=User&f%5B1%5D.Value=Azure%20AD%20Developer%20Experience%20Team&f%5B1%5D.Text=Azure%20AD%20Developer%20Experience%20Team

    可能会满足您的需求,或至少适应它们 .

  • 123

    我只是想知道为什么要使用一些库进行JWT令牌解码和验证 .

    可以使用following pseudocode创建编码的JWT令牌

    var headers = base64URLencode(myHeaders);
    var claims = base64URLencode(myClaims);
    var payload = header + "." + claims;
    
    var signature = base64URLencode(HMACSHA256(payload, secret));
    
    var encodedJWT = payload + "." + signature;
    

    没有任何特定的库很容易做到 . 使用以下代码:

    using System;
    using System.Text;
    using System.Security.Cryptography;
    
    public class Program
    {   
        // More info: https://stormpath.com/blog/jwt-the-right-way/
        public static void Main()
        {           
            var header = "{\"typ\":\"JWT\",\"alg\":\"HS256\"}";
            var claims = "{\"sub\":\"1047986\",\"email\":\"jon.doe@eexample.com\",\"given_name\":\"John\",\"family_name\":\"Doe\",\"primarysid\":\"b521a2af99bfdc65e04010ac1d046ff5\",\"iss\":\"http://example.com\",\"aud\":\"myapp\",\"exp\":1460555281,\"nbf\":1457963281}";
    
            var b64header = Convert.ToBase64String(Encoding.UTF8.GetBytes(header))
                .Replace('+', '-')
                .Replace('/', '_')
                .Replace("=", "");
            var b64claims = Convert.ToBase64String(Encoding.UTF8.GetBytes(claims))
                .Replace('+', '-')
                .Replace('/', '_')
                .Replace("=", "");
    
            var payload = b64header + "." + b64claims;
            Console.WriteLine("JWT without sig:    " + payload);
    
            byte[] key = Convert.FromBase64String("mPorwQB8kMDNQeeYO35KOrMMFn6rFVmbIohBphJPnp4=");
            byte[] message = Encoding.UTF8.GetBytes(payload);
    
            string sig = Convert.ToBase64String(HashHMAC(key, message))
                .Replace('+', '-')
                .Replace('/', '_')
                .Replace("=", "");
    
            Console.WriteLine("JWT with signature: " + payload + "." + sig);        
        }
    
        private static byte[] HashHMAC(byte[] key, byte[] message)
        {
            var hash = new HMACSHA256(key);
            return hash.ComputeHash(message);
        }
    }
    

    令牌解码是上面代码的反转版本 . 要验证签名,您需要相同并将签名部分与计算的签名进行比较 .

    更新:对于那些如何努力如何做base64 urlsafe编码/解码请看另一个SO question,还有维基和RFC

相关问题