asp.net-core - 在 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();
}
知道如何以及从哪里开始吗?
解决方案
您可以在调用远程 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。
更多信息请看这里。
推荐阅读
- java - Cucumber 在 4.7 中已弃用 Given/Then/When - 它们应该被什么替换?
- reactjs - 在 Jest 中编写手动模拟时如何键入调用 genMockFromModule 的结果?
- terraform - Input Environment Variables not being read
- javascript - 如何裁剪当前为 dataURL 的图像?
- wolfram-mathematica - 如何在 Mathematica 中绘制阶跃函数?
- asp-classic - 具有多个没有值的 URL 参数的 ASP 不存在键
- javascript - 我无法在 Parse.User.currentAsync().then(function(user)){} 之外传递当前用户
- epoch - Micropython 和 EPOCH
- itext7 - iText 7 - 当页面旋转值不是纵向时,将 PdfWatermarkAnnotation 标头定向为纵向
- javascript - SetTimeout 和 ScrollTop 的奇怪行为