首页 > 解决方案 > 在 Web API Core 3.1 中实现刷新令牌

问题描述

我需要在我的 Web API 中实现刷新令牌。我找到了这篇文章,所以我需要进一步详细说明刷新令牌的实现。同样,我找到了一些教程如何做到这一点,但我不知道如何从我的用例开始。这是我的 Auth 控制器中负责登录和生成令牌的操作:

[HttpPost]
        [Route("login")]
        public async Task<IActionResult> Login([FromBody] LoginModel model)
        {
            var user = await userManager.FindByNameAsync(model.Username);
            if (user != null &&
                await userManager.CheckPasswordAsync(user, model.Password) &&
                await userManager.IsEmailConfirmedAsync(user))
            {
                var userRoles = await userManager.GetRolesAsync(user);

                var authClaims = new List<Claim>
                {
                    new Claim(ClaimTypes.Name, user.UserName),
                    new Claim(JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString()),
                };

                foreach (var userRole in userRoles)
                {
                    authClaims.Add(new Claim(ClaimTypes.Role, userRole));
                }

                var authSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_configuration["JWT:Secret"]));

                var token = new JwtSecurityToken(
                    issuer: _configuration["JWT:ValidIssuer"], // The first parameter is a simple string representing the name of the webserver that issues the token
                    audience: _configuration["JWT:ValidAudience"], // The second parameter is a string value representing valid recipients
                    expires: DateTime.UtcNow.AddSeconds(15), // DateTime object that represents the date and time after which the token expires
                    claims: authClaims, // a list of user roles, for example, the user can be an admin, manager or author
                    signingCredentials: new SigningCredentials(authSigningKey, SecurityAlgorithms.HmacSha256)
                    );

                return Ok(new
                {
                    token = new JwtSecurityTokenHandler().WriteToken(token),
                    dateTimeNow = DateTime.UtcNow,
                    expiration = token.ValidTo
                });
            }
            return Unauthorized();
        }

知道如何以及从哪里开始吗?

标签: asp.net-coreauthenticationwebapi

解决方案


您可以在调用远程 API 的方法上实现 try/catch,一旦由于令牌过期而失败,您可以启动刷新令牌的更新并重试。

像这样:

        public async Task<TResponse> ExecuteWithRetryAsync<TResponse>(Func<Task<TResponse>> webApiCallMethod)
        {
            var tryForceRefreshToken = false;
            var attemptsCounter = 1;
            while (true)
            {
                if (tryForceRefreshToken)
                {
                    var success = await TryAuthWithRefreshTokenAsync();
                }
                try
                {
                    attemptsCounter++;

                    var response = await webApiCallMethod.Invoke();
                    return response;
                }
                catch (HttpRequestException)
                {
                    if (attemptsCounter > 2)
                    {
                        throw;
                    }
                    tryForceRefreshToken = true;
                }
                catch (Exception)
                {
                    throw;
                }
            }
        }

并且一旦失败,您就会尝试执行 TryAuthWithRefreshTokenAsync 一种尝试使用过期不记名令牌刷新令牌的方法,如下所示:

        private async Task<bool> TryAuthWithRefreshTokenAsync()
        {
            try
            {
                //Tenta executar o refreshtoken apenas da primeira thread que solicitou...
                //Para as demais threads, faz com que elas aguardem pela renovacao do token.
                if (Interlocked.CompareExchange(ref _refreshTokenEntered, 1, 0) == 0)
                {

                    Console.WriteLine("Refresh Token Renewing...");
                    //tenta renovar
                    var authResponse = await AuthWithRefreshTokenAsync();
                  
                    Interlocked.Exchange(ref _refreshTokenEntered, 0);
                    Console.WriteLine("Refresh Token Renewed");
                    return authResponse.Success;
                }
                else
                {
                    Console.WriteLine("Refresh Token Renewal is Waiting...");

                    while (_refreshTokenEntered == 1)
                    {
                        await Task.Delay(100);
                    }
                    //Faz as outras threads aguardarem até que o token seja renovado no bloco anterior
                    Console.WriteLine("Refresh Token Renewal done!");
                    return true;
                }
            }
            
            catch (Exception)
            {
                Interlocked.Exchange(ref _refreshTokenEntered, 0);
                throw;
            }

        }

在成功更新不记名令牌后,ExecuteWithRetryAsync 方法可以重试并调用您的远程 Web api。

更多信息请看这里


推荐阅读