为啥我的 JWT 不记名身份验证在令牌说 5 分钟后将令牌识别为过期?

Posted

技术标签:

【中文标题】为啥我的 JWT 不记名身份验证在令牌说 5 分钟后将令牌识别为过期?【英文标题】:Why is my JWT bearer authentication recognizing tokens as expired 5 minutes after the token says?为什么我的 JWT 不记名身份验证在令牌说 5 分钟后将令牌识别为过期? 【发布时间】:2017-03-01 18:03:23 【问题描述】:

我正在使用 AspNet.Security.OpenIdConnect.Server 来发布 JWT 令牌并将 AuthorizationCodeLifetime 设置为 30 秒以进行测试。这是我用来设置选项的代码的 sn-p

        options.TokenEndpointPath = "/api/token";
        options.AllowInsecureHttp = true;
        options.AccessTokenHandler = new JwtSecurityTokenHandler();
        options.SigningCredentials.Add(new SigningCredentials(signingKey, SecurityAlgorithms.HmacSha256));
        options.AccessTokenLifetime = TimeSpan.FromSeconds(30);
        options.AuthorizationCodeLifetime = TimeSpan.FromSeconds(30);

返回的令牌包含:

  "expires_in": 30,

并且反序列化的令牌包含以下声明:

 "nbf": 1476915220,
 "exp": 1476915250,
 "iat": 1476915220,

如您所见,exp(到期时间)是 iat(发布时间)之后的 30 秒。然而,令牌在过期 5 分钟后才会触发 401 Unauthorized。如果我们将 exp 编号插入 http://www.epochconverter.com/,那么我们将看到它的计算结果为 2016 年 10 月 19 日星期三 22:14:10 GMT,即我当地时间下午 5:14:10。

以下是核心库的一些记录输出:

Microsoft.IdentityModel.Tokens.SecurityTokenExpiredException: IDX10223: Lifetime validation failed. The token is expired.
ValidTo: '10/19/2016 22:14:10'
Current time: '10/19/2016 22:19:10'.
   at Microsoft.IdentityModel.Tokens.Validators.ValidateLifetime(Nullable`1 notBefore, Nullable`1 expires, SecurityToken securityToken, TokenValidationParameters validationParameters)
   at System.IdentityModel.Tokens.Jwt.JwtSecurityTokenHandler.ValidateLifetime(Nullable`1 notBefore, Nullable`1 expires, JwtSecurityToken securityToken, TokenValidationParameters validationParameters)
   at System.IdentityModel.Tokens.Jwt.JwtSecurityTokenHandler.ValidateToken(String token, TokenValidationParameters validationParameters, SecurityToken& validatedToken)
   at Microsoft.AspNetCore.Authentication.JwtBearer.JwtBearerHandler.<HandleAuthenticateAsync>d__1.MoveNext()
info: Microsoft.AspNetCore.Authentication.JwtBearer.JwtBearerMiddleware[7]
      Bearer was not authenticated. Failure message: IDX10223: Lifetime validation failed. The token is expired.
ValidTo: '10/19/2016 22:14:10'
Current time: '10/19/2016 22:19:10'.

当然,这个输出并不能证明服务器在 22:14:10 到 22:19:10 之间接受了令牌。如果我碰巧在它过期后等待了 5 分钟然后尝试验证令牌,这就是它会做的事情,但你必须相信我的话。我在 Postman 中进行测试,每秒都点击“发送”,直到它返回 401。

那么,怎么了?是否有一些我不知道的内置 5 分钟缓冲区?有趣的是,AccessTokenLifetime 的默认值为 5 分钟,但令牌肯定反映了我已将其更改为 30 秒。怎么回事?

我正在使用的相关库:

<package id="AspNet.Security.OpenIdConnect.Extensions" version="1.0.0-beta6-final" targetFramework="net452" />
<package id="AspNet.Security.OpenIdConnect.Server" version="1.0.0-beta6-final" targetFramework="net452" />
<package id="Microsoft.AspNetCore.Authentication.JwtBearer" version="1.0.0" targetFramework="net452" />

【问题讨论】:

刚刚遇到同样的问题,必须先在此处发布问题之前进行出色的调查,并附上一个简单明了的答案 :-) 干得好! 【参考方案1】:

那么,怎么了?是否有一些我不知道的内置 5 分钟缓冲区?怎么回事?

所谓的“缓冲区”实际上是 JWT 承载中间件(由 Microsoft 开发)提供的一种内置功能,称为“时钟偏差”,旨在​​减轻网络农场中时钟不同步的影响。

如你所见,the default value is set to 5 minutes,但可以通过 JwtBearerOptions.TokenValidationParameters.ClockSkew 更改。

【讨论】:

【参考方案2】:

我试过 ClockSkew = TimeSpan.Zero:

new TokenValidationParameters
    
                ClockSkew = TimeSpan.Zero
    ;

原因是 ClockSkew 的默认值为 5 分钟

【讨论】:

以上是关于为啥我的 JWT 不记名身份验证在令牌说 5 分钟后将令牌识别为过期?的主要内容,如果未能解决你的问题,请参考以下文章

添加基于策略的授权会跳过 JWT 不记名令牌身份验证检查吗?

实施 Identity 2.1 + OWIN OAuth JWT 不记名令牌时如何从 Web API 控制器端点进行身份验证

ASP.NET Core API 使用 JWT 不记名令牌进行身份验证

当我在授权标头中发送有效的不记名令牌时,为啥我的 Spring-Cloud Gateway / OAuth2-Client 没有通过身份验证?

如何使用 B2C 和 Blazor 获取 JWT 不记名令牌

使用 JWT Bearer 令牌进行身份验证 Swagger