工具:.NET 6 和 EF Core,Vue 3 和 Axios。
R-Token 是重繪 令牌。DB是資料庫。
我有 JWT Refresh Token auth 的簡單實作。
- 客戶發送登錄名和密碼。
- 檢查資料庫中的密碼哈希。
- 如果 OK,生成 JWT 令牌(生命周期短,1-5 分鐘)和重繪 令牌(生命周期長,365 天)保存到資料庫。
- 客戶端使用 JWT 發出請求。
- 當 Axios 攔截器收到 401 時,嘗試使用下面生成的 Refresh Token 來重繪 令牌。
- 已使用的 Refresh 令牌從 DB 中洗掉,如果應用程式在 DB 中找不到 R-Token,它會回應 403。
- ??
所以,在客戶端,我有一些呼叫服務器的間隔操作。有時,它們會同時執行,如果 JWT 令牌過期,我很少收到使用相同 R 令牌同時重繪 令牌的請求。
問題是: 在這種情況下,第一個請求會洗掉 R-token 并生成新的,然后下一個請求將失敗。
這個問題我該怎么辦?
我對此的看法:
- 在 Axios 攔截器中執行類似單例的操作。
- 在后端控制器中以某種方式使用 .NET 鎖結構,但用于單獨的客戶端。
請幫忙。
Axios 攔截器:
instance.interceptors.response.use(response => response,
async (error) => {
const status = error.response ? error.response.status : undefined
const originalRequest = error.config
if(status === 401) {
originalRequest._retry = true
let tryRefresh = await store.dispatch('auth/TryRefreshToken')
if(tryRefresh === false) {
store.dispatch('auth/Logout')
return Promise.reject(error)
}
originalRequest.headers['Authorization'] = 'Bearer ' store.getters['auth/auth'].accessToken
return instance(originalRequest)
}
if (status === undefined)
{
return Promise.reject(error)
}
return Promise.reject(error)
}
)
控制器中的 .NET 重繪 令牌操作:
[HttpPost, Route("Refresh/{refreshToken}")]
[ProducesResponseType(typeof(AuthenticationResponse), 200)]
public IActionResult RefreshTokens(string refreshToken)
{
Request.Headers.TryGetValue("Authorization", out var accessTokenHeader);
string? accessToken = accessTokenHeader.FirstOrDefault()?.Replace("Bearer", string.Empty).Trim();
if (string.IsNullOrEmpty(accessToken)) return BadRequest("No access token presented.");
JwtSecurityToken? expiredToken = new JwtSecurityTokenHandler().ReadToken(accessToken) as JwtSecurityToken;
if (expiredToken is null) return BadRequest("Bad access token format");
IEnumerable<Claim> claims = expiredToken.Claims;
if (int.TryParse(claims.FirstOrDefault(x => x.Type == "User:Id")?.Value, out int userId) is false)
return BadRequest("No user id in token presented");
User? user = _mainContext.Users.AsNoTrackingWithIdentityResolution()
.Include(x => x.Roles)
.FirstOrDefault(x => x.Id == userId);
if (user is null) return NotFound("No user found");
var userDto = user.ToUserDto();
if (_refreshTokenManager.IsTokenValid(refreshToken, user.Id) is false)
return StatusCode(403);
try {
_refreshTokenManager.RemoveToken(refreshToken);
}
catch (Exception ex) {
Log.Error(ex, "Error in used refresh token deletion.");
}
JwtSettingsDto jwtSettings = _configuration.GetSection("Authorization:Jwt").Get<JwtSettingsDto>();
string newAccessToken = _tokenGeneratorService.GenerateAccessJwtToken(userDto, jwtSettings);
string newRefreshToken = _refreshTokenManager.CreateToken(userDto, Request);
return Ok(new AuthenticationResponse(newAccessToken, newRefreshToken, user.Login, user.DisplayName));
}
uj5u.com熱心網友回復:
當重繪 令牌有一次性使用時,這幾天推薦使用,同步令牌重繪 是客戶端的責任。如果多個視圖同時呼叫 API,則 UI 需要這樣做。
在一個實用程式類中執行此操作相當容易,該實用程式類對令牌重繪 的承諾進行排隊,然后只對其中的第一個進行實際的 HTTP 呼叫,然后為所有請求回傳相同的結果。
例如,請參閱我的這個 ConcurrentActionHandler 類,在 React SPA 中使用,它是從此 API 客戶端代碼呼叫的。
在您的情況下,Michael Levy 發布的攔截器類似乎做了同樣的作業。所以這可能是最好的選擇。但是,相同的設計模式可以應用于其他型別的客戶端,例如用 Swift 或 Kotlin 編碼的移動應用程式。
轉載請註明出處,本文鏈接:https://www.uj5u.com/net/474953.html
