当前位置: 首页 > 知识库问答 >
问题:

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

鲁品
2023-03-14

我一直在使用JWT库解码一个Json Web令牌,并希望切换到微软的官方JWT实现system . identity model . tokens . jwt

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

值得一提的是,我正在从cookie中读取JWT令牌,以便与谷歌的身份框架一起使用。

任何帮助都将不胜感激。

共有3个答案

欧阳安阳
2023-03-14

我在System.IdentityModel.Tokens和System.IdentityModel.Tokens.Jwt之间遇到了版本问题,这是Jwt版本5.0.0.0之后的已知问题。因此,我下载了最新版本的Microsoft.IdentityModel.Tokens(注意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
乐欣可
2023-03-14

我只是想知道为什么要使用一些库来进行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 urlsafe编码/解码的人,请参见另一个SO问题,以及wiki和RFC

师博
2023-03-14

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

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

SecurityTokenHandler还有一个ValidateToken(SecurityToken)方法,它接受您的SecurityToken并创建一个ReadOnly集合

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

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

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

或者,JwtSecurityToken类具有不在SecurityToken类基础上的其他方法,例如 property,它不通过 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[0].类型=搜索文本

很可能,其中一个会适合你的需求,或者至少可以适应它们。

 类似资料:
  • 我目前正在使用Vapor开发Swift后端。我的iOS客户端使用新的iOS 13功能“使用Apple登录”。当用户登录时,我会得到一个身份令牌(访问令牌),这是一个由Apple签名的有效JWT令牌。这将在所有正在进行的通信中发送到服务器,以验证服务器提供的某些路由。 在服务器上,我想通过验证令牌签名来验证发送的令牌是否确实由Apple签名,并且不是由某些恶意用户专门创建的。Apple提供了一个HT

  • 我正在阅读JWT的示例文件夹,我有点不确定验证令牌的工作原理。 这里直接使用“mySigningKey”在中签名 现在,对我来说,未解析就不那么清楚了: 是为了验证客户端返回的令牌字符串的签名是否有效,您是否需要 解码声明(在&MyCustomClaims{}中完成) 使用token.valid验证解码声明的签名部分对“令牌中包含的pub密钥”是否有效。 但这个例子只是解码密钥,通过“魔术”返回的

  • 在我的Jitsi Meet Prodody配置文件中:~/。jitsi meet cfg/prosody/config/conf.d 我有以下配置: 有了它,我可以通过令牌进行身份验证。 但是,如果我不指定任何令牌,例如: https://jitsi.mydummyserver.com/test 然后我得到以下提示询问用户和密码: 有没有办法只允许令牌身份验证并完全摆脱那个提示? 谢谢

  • 我正在做一个项目(没有生产级别,只是为了提高我的技能),我正在使用JWT来处理身份验证。从我所读到的内容来看,仅使用JWT作为访问令牌是非常不安全的,因此我们需要刷新令牌。因此,在登录时,服务器返回一个访问令牌和一个刷新令牌(我将存储在httpOnly cookie中)。访问令牌在短时间内到期,但刷新令牌在到期时用于获取新令牌。 我的问题是,我们何时使用刷新令牌来获取新的访问令牌?是当用户想要获得

  • 我正在制作一个javascript客户端,它使用JWT令牌连接到Api。在服务器端没有问题,我可以创建令牌对其进行签名,然后验证签名,从而确保没有人篡改令牌。 但我如何在客户端做到这一点。我可以解码JWT令牌并查看头、负载和签名。但是如何在客户端验证签名?是否有用于此的库,如何将公钥传输到客户端? 如果我不验证签名,我怎么知道令牌没有被篡改?