JWT令牌认证,过期的令牌仍然有效,.net core Web Api

74
我正在构建一个 .net core web api。
前言 - 我已按照 https://stormpath.com/blog/token-authentication-asp-net-corehttps://dev.to/samueleresca/developing-token-authentication-using-aspnet-core 实现了令牌身份验证。我也在 github 和这里的 SO 上阅读了一些问题。 https://goblincoding.com/2016/07/24/asp-net-core-policy-based-authorisation-using-json-web-tokens/ 也很有用。
在实现所有这些之后,我感觉好像还缺少了些什么。
我创建了一个简单的 Angular 应用程序,它位于 Web 客户端中。当我进行身份验证时,客户端会收到一个令牌。我现在将其存储在会话中(仍在开发中,稍后将解决关于在哪里存储的安全问题)。
我不太确定这个(JWT (JSON Web Token) automatic prolongation of expiration)是否有用,因为我没有实现刷新令牌。
我注意到当我注销并再次登录时,客户端会收到一个新的令牌,这是预期的。然而,如果令牌过期时间已经过去(我将其设置为1分钟进行测试),然后刷新页面,令牌似乎在我的应用程序中保持不变。换句话说,就好像令牌从未过期一样?!
我本来期望客户端会返回401未授权错误,然后我可以处理强制用户重新验证身份。
这不是它应该工作的方式吗?后台是否有自动刷新令牌的魔法(我没有明确地在教程中设置任何刷新令牌的概念)?还是我对令牌认证的概念存在误解?
另外,如果这是一个永久刷新的令牌,那么如果令牌被泄露,我应该担心安全问题吗?
感谢您的帮助。
4个回答

135

我认为这与JwtBearerOptions中的ClockSkew有关。

将其更改为TimeSpan.Zero,因为我认为默认设置为5分钟(尽管不确定)。

我在下面发布了一些示例代码,应将其放置在Startup.cs => Configure中。

        app.UseJwtBearerAuthentication(new JwtBearerOptions()
        {
            AuthenticationScheme = "Jwt",
            AutomaticAuthenticate = true,
            AutomaticChallenge = true,
            TokenValidationParameters = new TokenValidationParameters()
            {
                ValidAudience = Configuration["Tokens:Audience"],
                ValidIssuer = Configuration["Tokens:Issuer"],
                ValidateIssuerSigningKey = true,
                IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(Configuration["Tokens:Key"])),
                ValidateLifetime = true,
                ClockSkew = TimeSpan.Zero
            }
        });

请参阅 https://dev59.com/PFYN5IYBdhLWcg3wopUD 了解有关时钟偏差和令牌的信息。 - Michael Freidgeim

26

如果您的到期时间超过了默认值(5分钟)或超过了像我一样设置的时间,但它仍然将已过期的令牌视为有效,并且将ClockSkew设置为TimeSpan.Zero没有效果,请确保您拥有该属性。

ValidateLifetime 

由于我将其设置为false,导致了问题,所以将其设置为true,这完全合理,但这是一个很容易忽视的问题。

services.AddAuthentication(option =>
    {
        option.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
        option.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
    })
    .AddJwtBearer(options =>
    {
        options.TokenValidationParameters = new TokenValidationParameters
        {
            ValidateIssuer = true,
            ValidateAudience = true,
            ValidateLifetime = true,
            ValidateIssuerSigningKey = true,
            ValidIssuer = Configuration["JwtToken:Issuer"],
            ValidAudience = Configuration["JwtToken:Issuer"],
            IssuerSigningKey = new SymmetricSecurityKey(
               Encoding.UTF8.GetBytes(Configuration["JwtToken:SecretKey"]))
        };
    });

6
对我来说,我需要在Core 2.2中同时使用ValidateLifetime和ClockSkew。 - Michael K
1
我可以确认这在NetCore3.1中可行。有趣的是这在文档中并没有真正被记录:https://learn.microsoft.com/en-us/dotnet/api/microsoft.identitymodel.tokens.tokenvalidationparameters.clockskew?view=azure-dotnet。默认值为5分钟(请查看 https://learn.microsoft.com/en-us/dotnet/api/microsoft.identitymodel.tokens.tokenvalidationparameters.defaultclockskew?view=azure-dotnet)。 - FranzHuber23

18

图书馆内部还需要额外延迟5分钟。

如果您将过期时间设置为1分钟,则总时间将为6分钟。如果您将其设置为1小时,则总时间将为1小时5分钟。


3
你所说的“图书馆内额外延迟5分钟”是什么意思?你的意思是除了已经提到的“时钟偏差”之外还要再加上5分钟延迟吗? - jps
1
我觉得他指的是已经提到的 ClockSkew - FranzHuber23
也许吧,但是关于时钟偏差已经有一个好的、清晰的答案了,那么为什么我们还需要一个额外的、相当不清楚的答案呢? - jps
是的,我在谈论ClockSkew,这是我发现的一个例子。 - João Pedro Hudinik
https://learn.microsoft.com/en-us/dotnet/api/microsoft.identitymodel.tokens.tokenvalidationparameters.defaultclockskew?view=azure-dotnet - live2

0
在我的情况下,我添加了一个新的SecurityTokenDescriptor,其中包含属性,该属性采用当前日期和时间,并根据我们的要求设置过期时间。 以下是一个带有post请求的示例登录控制器,该控制器返回用户详细信息和令牌。
        public async Task<ActionResult<UserWithToken>> Login([FromBody] User user)
        {
             user = await _context.Users
                                    .Include(u => u.Reservations)
                                .Where(u => u.Email == user.Email
                                   && u.Password == user.Password)
                                .FirstOrDefaultAsync();

            if (user == null)
            {
                return NotFound();
            }

            UserWithToken userWithToken = new UserWithToken(user);

            if (userWithToken == null)
            {
                return NotFound();
            }

            var tokenHandler = new JwtSecurityTokenHandler();
            var key = Encoding.ASCII.GetBytes(_jwtsettings.SecretKey);
            var tokenDescriptor = new SecurityTokenDescriptor
            {
                Subject = new ClaimsIdentity(new Claim[]
                {
                    new Claim(ClaimTypes.Name, user.Email)
                }),
                Expires = DateTime.UtcNow.AddMinutes(10),
                SigningCredentials = new SigningCredentials(new SymmetricSecurityKey(key),
                SecurityAlgorithms.HmacSha256Signature)
            };
            var token = tokenHandler.CreateToken(tokenDescriptor);
            userWithToken.Token = tokenHandler.WriteToken(token);

            return userWithToken;
        }

这里的令牌将在10分钟后过期。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接