115

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

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

对于它的价值,我正在从 cookie 中读取 JWT 令牌,用于 Google 的身份框架。

任何帮助,将不胜感激。

4

3 回答 3

171

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

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

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

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

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

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

或者,JwtSecurityToken该类具有基SecurityToken类中没有的其他方法,例如Claims无需通过ClaimsIdentity集合即可获取包含声明的属性。它还有一个Payload属性,该属性返回一个JwtPayload对象,让您可以获取令牌的原始 JSON。这取决于您的方案最合适的方法。

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

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

可能,一个会满足您的需求,或者至少可以适应它们。

于 2013-09-18T20:59:21.693 回答
29

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

可以使用以下伪代码创建编码的 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 url​​safe 编码/解码的人,请参阅另一个SO question,以及 wiki 和 RFC

于 2016-03-22T09:06:04.537 回答
0

我在System.IdentityModel.Tokens和之间有版本问题System.IdentityModel.Tokens.Jwt,这是 Jwt 版本 5.0.0.0 之后的一个已知问题。因此,我下载了最新版本的Microsoft.IdentityModel.Tokens- note Microsoft,一切正常。这是我为验证和解码自定义生成的 JWT 令牌并解析其 JSON 内容而制作的一个很好的片段。

using System.Collections.Generic;
using System.Linq;
using Microsoft.IdentityModel.Tokens;
using System.IdentityModel.Tokens.Jwt;
using System.Security.Claims;

public static void Main()
{
    var key = "qwertyuiopasdfghjklzxcvbnm123456";
    var securityKey = new SymmetricSecurityKey(System.Text.Encoding.UTF8.GetBytes(key));

    string token = "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJPbmxpbmUgSldUIEJ1aWxkZXIiLCJpYXQiOjE2NDA0MDY1MjIsImV4cCI6MTY3MTk0MjUyMiwiYXVkIjoid3d3LmV4YW1wbGUuY29tIiwic3ViIjoianJvY2tldEBleGFtcGxlLmNvbSIsImZvbyI6ImJhciJ9.QqcxZWEUt5YLraLRg5550Ls7aMVqm7aCUcbU7uB1qgY";

    TokenValidationParameters tokenValidationParameters = new TokenValidationParameters
    {
        IssuerSigningKey = securityKey,
        RequireExpirationTime = true,
        ValidateLifetime = true,
        ValidateAudience = true,
        ValidateIssuer = true,
        ValidIssuer = "Online JWT Builder",
        ValidAudience = "www.example.com",
    };

    if (ValidateToken(token, tokenValidationParameters))
    {
        var TokenInfo = new Dictionary<string, string>();
        var handler = new JwtSecurityTokenHandler();
        var jwtSecurityToken = handler.ReadJwtToken(token);
        var claims = jwtSecurityToken.Claims.ToList();

        foreach (var claim in claims)
        {
            TokenInfo.Add(claim.Type, claim.Value);
        }

        string sub = jwtSecurityToken.Subject;
        string iss = jwtSecurityToken.Issuer;
        DateTime iat = jwtSecurityToken.IssuedAt;
        List<string> audiences = new List<string>(jwtSecurityToken.Audiences);
        DateTime exp = jwtSecurityToken.ValidTo;
        string bar;
        bool ifBar = TokenInfo.TryGetValue("foo", out bar);
        Console.WriteLine("Subject: " + sub);
        Console.WriteLine("Issuer: " + iss);
        Console.WriteLine("Issued At: " + iat);
        foreach (var member in audiences)
        {
            Console.WriteLine("Audience: " + member);
        }
        Console.WriteLine("Expiration: " + exp);
        Console.WriteLine("foo: " + bar);
    }
    Console.ReadLine();
}

private static bool ValidateToken(string token, TokenValidationParameters tvp)
{
    try
    {
        var handler = new JwtSecurityTokenHandler();
        SecurityToken securityToken;
        ClaimsPrincipal principal = handler.ValidateToken(token, tvp, out securityToken);
        return true;
    }
    catch (Exception ex)
    {
        Console.WriteLine(ex.Message);
        return false;
    }
}

输出

Subject: jrocket@example.com
Issuer: Online JWT Builder
Issued At: 12/25/2022 4:28:42 AM
Audience: www.example.com
Expiration: 12/25/2022 4:28:42 AM
foo: bar
于 2021-12-25T04:45:40.880 回答