如何读取已过期的 JWT 令牌

dfm*_*tro 6 c# jwt asp.net-core asp.net-core-webapi

我在 ASP.NET Core 2 Web API 项目中使用 JWT 令牌

我的前端 Web 客户端会发送一个 JWT 令牌,它最初是从 Web API 登录 API 中获取的,每个请求都能正常工作。不过,我还有一个离线客户端,它使用相同的 API,最初在线登录,然后离线存储 JWT,仅当用户同步应用程序时(可能是一周后)才发送它。令牌可能已过期或服务器 Web 应用程序在此期间重新启动。

如果 JWT 令牌由于离线客户端过期而失败,我仍然希望调用 Web API 控制器方法并User根据需要的用户名填充 ASP.NET Identity 对象。我将记录此事件,但我还需要过期/无效令牌中的用户名。目前,如果身份验证失败,将不会输入控制器方法,因此我添加一个 [AllowAnonymous] 属性,但这将导致 User.Identity 为空,因为我想要用户名

我的代码:

启动.cs

    public void ConfigureServices(IServiceCollection services)
    {

        services.AddAuthentication()
            .AddJwtBearer(cfg =>
            {
                cfg.TokenValidationParameters = new TokenValidationParameters()
                {
                    ValidIssuer = _config["Tokens:Issuer"],
                    ValidAudience = _config["Tokens:Audience"],
                    IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_config["Tokens:Key"]))
                };

            });
Run Code Online (Sandbox Code Playgroud)

当用户登录时

   private IActionResult CreateToken(ApplicationUser user, IList<string> roles)
    {
        var claims = new List<Claim>
        {
          new Claim(JwtRegisteredClaimNames.Sub, user.Id.ToString()),
          new Claim(JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString()),
          new Claim(JwtRegisteredClaimNames.UniqueName, user.UserName)
        };



        var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_config["Tokens:Key"]));

        var creds = new SigningCredentials(key, SecurityAlgorithms.HmacSha256);

        var token = new JwtSecurityToken(
          _config["Tokens:Issuer"],
          _config["Tokens:Audience"],
          claims.ToArray(),
         expires: DateTime.Now.AddMinutes(60),
          signingCredentials: creds);

        var results = new
        {
            token = new JwtSecurityTokenHandler().WriteToken(token),
            expiration = token.ValidTo,
        };

        return Created("", results);
Run Code Online (Sandbox Code Playgroud)

我确保经过身份验证后,各种 API 调用都会传递 JWT 令牌。

[Authorize(AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme)]
 public class MyController : Controller
{
Run Code Online (Sandbox Code Playgroud)

这允许我使用以下代码捕获登录用户的各种 API 调用

 var loggedInUser = User.Identity.Name;
Run Code Online (Sandbox Code Playgroud)

如果 JWT 令牌已过期或无效,如何从该令牌中读取用户名?

Abh*_*raf 2

如果您希望即使令牌已过期也能通过授权,您只需将其添加到即可禁用生命周期验证TokenValidationParameters

services.AddAuthentication()
        .AddJwtBearer(cfg =>
        {
            cfg.TokenValidationParameters = new TokenValidationParameters()
            {
                ValidIssuer = _config["Tokens:Issuer"],
                ValidAudience = _config["Tokens:Audience"],
                IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_config["Tokens:Key"]))

                //Do not check the expiry of token
                ValidateLifetime = false,
            };

        });
Run Code Online (Sandbox Code Playgroud)

这将确保授权中间件认为令牌有效,并填充User.IdentityMVC 中间件中的对象。

但是,此检查也会禁用您的 Web 客户端的过期检查。您必须确定适当的客户端(不能绝对完成)并检查控制器中的到期时间。

更好的方法是寻找更好的设计来解决您的基本需求。

令牌可能已过期或服务器 Web 应用程序在此期间重新启动

我对这个说法有点困惑。如果服务器 Web 应用程序同时重新启动并且您遇到令牌过期,我假设您正在使用临时签名密钥来签署 JWT 令牌。您应该改用永久签名密钥。

对于离线客户端,您需要长期令牌,请查看刷新令牌。刷新令牌通常具有较长的生命周期,并且可用于将其自身交换为更新的访问令牌。offline_access当指定范围时,标准 oauth2.0 实现会发出刷新令牌。范围名称应指示刷新令牌的常见用例。

您可以在授权服务器上将 Web 客户端和离线客户端配置为两个不同的客户端,从而确保只有离线客户端才会获得刷新令牌。