Добавьте файлы проекта.
This commit is contained in:
101
PlaylistShared.Pwa/Services/AuthStateProvider.cs
Normal file
101
PlaylistShared.Pwa/Services/AuthStateProvider.cs
Normal file
@@ -0,0 +1,101 @@
|
||||
using Microsoft.AspNetCore.Components.Authorization;
|
||||
using System.IdentityModel.Tokens.Jwt;
|
||||
using System.Net.Http.Headers;
|
||||
using System.Security.Claims;
|
||||
|
||||
namespace PlaylistShared.Pwa.Services;
|
||||
|
||||
public class AuthStateProvider : AuthenticationStateProvider, IDisposable
|
||||
{
|
||||
private readonly TokenStorage _tokenStorage;
|
||||
private readonly ApiClient _apiClient;
|
||||
private readonly HttpClient _http;
|
||||
private Timer? _refreshTimer;
|
||||
private ClaimsPrincipal _currentUser = new(new ClaimsIdentity());
|
||||
|
||||
public AuthStateProvider(TokenStorage tokenStorage, ApiClient apiClient, HttpClient http)
|
||||
{
|
||||
_tokenStorage = tokenStorage;
|
||||
_apiClient = apiClient;
|
||||
_http = http;
|
||||
}
|
||||
|
||||
public override async Task<AuthenticationState> GetAuthenticationStateAsync()
|
||||
{
|
||||
var (token, refreshToken) = await _tokenStorage.GetTokensAsync();
|
||||
if (string.IsNullOrEmpty(token))
|
||||
return new AuthenticationState(_currentUser);
|
||||
|
||||
var principal = ParseToken(token);
|
||||
if (principal == null)
|
||||
return new AuthenticationState(_currentUser);
|
||||
|
||||
_currentUser = principal;
|
||||
_http.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token);
|
||||
ScheduleTokenRefresh(token, refreshToken);
|
||||
return new AuthenticationState(principal);
|
||||
}
|
||||
|
||||
public async Task MarkUserAsAuthenticated(string token, string refreshToken)
|
||||
{
|
||||
await _tokenStorage.SetTokensAsync(token, refreshToken);
|
||||
var principal = ParseToken(token);
|
||||
_currentUser = principal ?? new ClaimsPrincipal(new ClaimsIdentity());
|
||||
_http.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token);
|
||||
NotifyAuthenticationStateChanged(GetAuthenticationStateAsync());
|
||||
}
|
||||
|
||||
public async Task MarkUserAsLoggedOut()
|
||||
{
|
||||
await _tokenStorage.ClearTokensAsync();
|
||||
_currentUser = new ClaimsPrincipal(new ClaimsIdentity());
|
||||
_http.DefaultRequestHeaders.Authorization = null;
|
||||
NotifyAuthenticationStateChanged(GetAuthenticationStateAsync());
|
||||
}
|
||||
|
||||
private ClaimsPrincipal? ParseToken(string token)
|
||||
{
|
||||
try
|
||||
{
|
||||
var handler = new JwtSecurityTokenHandler();
|
||||
var jwt = handler.ReadJwtToken(token);
|
||||
var identity = new ClaimsIdentity(jwt.Claims, "jwt");
|
||||
return new ClaimsPrincipal(identity);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private void ScheduleTokenRefresh(string token, string? refreshToken)
|
||||
{
|
||||
var handler = new JwtSecurityTokenHandler();
|
||||
var jwt = handler.ReadJwtToken(token);
|
||||
var expiresAt = jwt.ValidTo;
|
||||
var timeToExpiry = expiresAt - DateTime.UtcNow;
|
||||
var refreshTime = timeToExpiry - TimeSpan.FromMinutes(5);
|
||||
|
||||
if (refreshTime > TimeSpan.Zero && !string.IsNullOrEmpty(refreshToken))
|
||||
{
|
||||
_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();
|
||||
}
|
||||
}, null, (int)refreshTime.TotalMilliseconds, Timeout.Infinite);
|
||||
}
|
||||
}
|
||||
|
||||
public void Dispose() => _refreshTimer?.Dispose();
|
||||
}
|
||||
Reference in New Issue
Block a user