Добавлено обновление jwt при входи в систему

This commit is contained in:
FrigaT
2026-04-22 09:28:16 +03:00
parent e2e117a539
commit c32eee0954

View File

@@ -12,6 +12,8 @@ public class AuthStateProvider : AuthenticationStateProvider, IDisposable
private readonly HttpClient _http;
private Timer? _refreshTimer;
private ClaimsPrincipal _currentUser = new(new ClaimsIdentity());
private string? _currentToken;
private string? _currentRefreshToken;
public AuthStateProvider(TokenStorage tokenStorage, ApiClient apiClient, HttpClient http)
{
@@ -26,14 +28,59 @@ public class AuthStateProvider : AuthenticationStateProvider, IDisposable
if (string.IsNullOrEmpty(token))
return new AuthenticationState(_currentUser);
var principal = ParseToken(token);
if (principal == null)
return new AuthenticationState(_currentUser);
var (isValid, principal) = await ValidateTokenAsync(token);
if (isValid && principal != null)
{
_currentUser = principal;
_currentToken = token;
_currentRefreshToken = refreshToken;
_http.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token);
ScheduleTokenRefresh(token, refreshToken);
return new AuthenticationState(principal);
}
_currentUser = principal;
_http.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token);
ScheduleTokenRefresh(token, refreshToken);
return new AuthenticationState(principal);
// Токен невалиден пробуем обновить
if (!string.IsNullOrEmpty(refreshToken))
{
var newTokenResponse = await _apiClient.RefreshTokenAsync(refreshToken);
if (newTokenResponse != null && !string.IsNullOrEmpty(newTokenResponse.Token))
{
await MarkUserAsAuthenticated(newTokenResponse.Token, newTokenResponse.RefreshToken);
// После MarkUserAsAuthenticated состояние обновится через NotifyAuthenticationStateChanged,
// но текущий вызов всё равно должен вернуть нового пользователя
var (newIsValid, newPrincipal) = await ValidateTokenAsync(newTokenResponse.Token);
if (newIsValid && newPrincipal != null)
return new AuthenticationState(newPrincipal);
}
}
// Всё плохо — логаут
await MarkUserAsLoggedOut();
return new AuthenticationState(_currentUser);
}
// Вспомогательный метод проверки валидности токена (включая срок)
private async Task<(bool IsValid, ClaimsPrincipal? Principal)> ValidateTokenAsync(string token)
{
try
{
var handler = new JwtSecurityTokenHandler();
var jwt = handler.ReadJwtToken(token);
// Проверяем, не истёк ли токен
if (jwt.ValidTo < DateTime.UtcNow)
{
return (false, null);
}
var identity = new ClaimsIdentity(jwt.Claims, "jwt");
var principal = new ClaimsPrincipal(identity);
return (true, principal);
}
catch
{
return (false, null);
}
}
public async Task MarkUserAsAuthenticated(string token, string refreshToken)
@@ -41,6 +88,8 @@ public class AuthStateProvider : AuthenticationStateProvider, IDisposable
await _tokenStorage.SetTokensAsync(token, refreshToken);
var principal = ParseToken(token);
_currentUser = principal ?? new ClaimsPrincipal(new ClaimsIdentity());
_currentToken = token;
_currentRefreshToken = refreshToken;
_http.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token);
NotifyAuthenticationStateChanged(GetAuthenticationStateAsync());
}
@@ -49,10 +98,51 @@ public class AuthStateProvider : AuthenticationStateProvider, IDisposable
{
await _tokenStorage.ClearTokensAsync();
_currentUser = new ClaimsPrincipal(new ClaimsIdentity());
_currentToken = null;
_currentRefreshToken = null;
_http.DefaultRequestHeaders.Authorization = null;
_refreshTimer?.Dispose();
NotifyAuthenticationStateChanged(GetAuthenticationStateAsync());
}
public async Task<string?> TryRefreshTokenAsync()
{
if (string.IsNullOrEmpty(_currentRefreshToken))
return null;
try
{
var newToken = await _apiClient.RefreshTokenAsync(_currentRefreshToken);
if (newToken != null && !string.IsNullOrEmpty(newToken.Token))
{
await MarkUserAsAuthenticated(newToken.Token, newToken.RefreshToken);
return newToken.Token;
}
else
{
await MarkUserAsLoggedOut();
return null;
}
}
catch
{
await MarkUserAsLoggedOut();
return null;
}
}
public bool IsTokenExpiringSoon()
{
if (string.IsNullOrEmpty(_currentToken))
return false;
var handler = new JwtSecurityTokenHandler();
var jwt = handler.ReadJwtToken(_currentToken);
var expiresAt = jwt.ValidTo;
var timeToExpiry = expiresAt - DateTime.UtcNow;
return timeToExpiry < TimeSpan.FromMinutes(1);
}
private ClaimsPrincipal? ParseToken(string token)
{
try
@@ -62,7 +152,7 @@ public class AuthStateProvider : AuthenticationStateProvider, IDisposable
var identity = new ClaimsIdentity(jwt.Claims, "jwt");
return new ClaimsPrincipal(identity);
}
catch (Exception ex)
catch
{
return null;
}
@@ -81,18 +171,7 @@ public class AuthStateProvider : AuthenticationStateProvider, IDisposable
_refreshTimer?.Dispose();
_refreshTimer = new Timer(async _ =>
{
try
{
var newToken = await _apiClient.RefreshTokenAsync(refreshToken);
if (newToken != null)
await MarkUserAsAuthenticated(newToken.Token, newToken.RefreshToken);
else
await MarkUserAsLoggedOut();
}
catch
{
await MarkUserAsLoggedOut();
}
await TryRefreshTokenAsync();
}, null, (int)refreshTime.TotalMilliseconds, Timeout.Infinite);
}
}