如何在asp.net核心Web API(无第三方)中实现JWT刷新令牌? [英] How to implement JWT Refresh Tokens in asp.net core web api (no 3rd party)?

查看:54
本文介绍了如何在asp.net核心Web API(无第三方)中实现JWT刷新令牌?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用使用JWT的asp.net核心来实现Web api.我在尝试学习时没有使用诸如IdentityServer4之类的第三方解决方案.

I'm in the process of implementing a web api using asp.net core that is using JWT. I am not using a third party solution such as IdentityServer4 as I am trying to learn.

我已经使用了JWT配置,但是对于如何在JWT过期时实现刷新令牌感到困惑.

I've gotten the JWT configuration to work, but am stumped on how to implement refresh tokens for when the JWT's expire.

下面是我在startup.cs内的Configure方法中的一些示例代码.

Below is some sample code in my Configure method inside startup.cs.

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
    }
});

下面是用于生成JWT的Controller方法.我已将到期时间设置为30秒以用于测试.

Below is the Controller method used to generate the JWT. I have set expiration to 30 seconds for testing purposes.

    [Route("Token")]
    [HttpPost]
    public async Task<IActionResult> CreateToken([FromBody] CredentialViewModel model)
    {
        try
        {
            var user = await _userManager.FindByNameAsync(model.Username);

            if (user != null)
            {
                if (_hasher.VerifyHashedPassword(user, user.PasswordHash, model.Password) == PasswordVerificationResult.Success)
                {
                    var userClaims = await _userManager.GetClaimsAsync(user);

                    var claims = new[]
                    {
                        new Claim(JwtRegisteredClaimNames.Sub, user.UserName),
                        new Claim(JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString())
                    }.Union(userClaims);

                    var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_jwt.Key));
                    var creds = new SigningCredentials(key, SecurityAlgorithms.HmacSha256);

                    var token = new JwtSecurityToken(
                            issuer: _jwt.Issuer,
                            audience: _jwt.Audience,
                            claims: claims,
                            expires: DateTime.UtcNow.AddSeconds(30),
                            signingCredentials: creds
                        );

                    return Ok(new
                    {
                        access_token = new JwtSecurityTokenHandler().WriteToken(token),
                        expiration = token.ValidTo
                    });
                }
            }
        }
        catch (Exception)
        {

        }

        return BadRequest("Failed to generate token.");
    }

非常感谢您提供一些指导.

Would be very grateful for some guidance.

推荐答案

首先,您需要生成刷新令牌并将其保存在某个地方.这是因为您希望能够在需要时使其无效.如果您要遵循与访问令牌相同的模式-所有数据都包含在该令牌中-最终使用不正确的令牌可能会在刷新令牌的整个生命周期内用于生成新的访问令牌,可能会很长一段时间.

First of all, you need to generate a refresh token and persist it somewhere. This is because you want to be able to invalidate it if needed. If you were to follow the same pattern as an access token - where all the data is contained within the token - a token that ends up in the wrong hands can the be used to generate new access tokens for the lifetime of the refresh token, which can be a really long time.

那你需要坚持什么呢?

您需要某种不容易猜测的唯一标识符,GUID可以正常工作.您还需要数据才能发出新的访问令牌,最有可能是用户名.拥有用户名之后,您可以跳过VerifyHashedPassword(...)部分,但对于其余部分,只需遵循相同的逻辑即可.

You need a unique identifier of some sort that's not easy guessable, a GUID will do just fine. You also need the data to be able to issue a new access token, most likely a username. Having a username you can then skip the VerifyHashedPassword(...)-part but for the rest of it, just follow the same logic.

要获取刷新令牌,通常使用范围"offline_access",这是您在发出令牌请求时在模型(CredentialViewModel)中提供的内容.与普通访问令牌请求不同,您无需提供用户名和密码,而需要提供刷新令牌.在获得带有刷新令牌的请求时,您将查找持久标识符并为找到的用户颁发令牌.

To obtain a refresh token, you normally use the scope "offline_access", this being something that you provide in your model (CredentialViewModel) when making a token request. Unlike a normal access token request, you don't need to provide your username and password, but instead the refresh token. When getting a request with a refresh token, you lookup the persisted identifier and issue a token for the user found.

以下是快乐路径的伪代码:

Following is pseudo code for the happy path:

[Route("Token")]
[HttpPost]
public async Task<IActionResult> CreateToken([FromBody] CredentialViewModel model)
{
    if (model.GrantType is "refresh_token")
    {
        // Lookup which user is tied to model.RefreshToken
        // Generate access token from the username (no password check required)
        // Return the token (access + expiration)
    }
    else if (model.GrantType is "password")
    {
        if (model.Scopes contains "offline_access")
        {
            // Generate access token
            // Generate refresh token (random GUID + model.username)
            // Persist refresh token
            // Return the complete token (access + refresh + expiration)
        }
        else
        {
            // Generate access token
            // Return the token (access + expiration)
        }
    }
}

这篇关于如何在asp.net核心Web API(无第三方)中实现JWT刷新令牌?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆