Initial commit - Auth.RCL
This commit is contained in:
Executable
+166
@@ -0,0 +1,166 @@
|
||||
using System.Net.Http.Headers;
|
||||
using System.Net.Http.Json;
|
||||
using System.Security.Claims;
|
||||
using System.Text;
|
||||
using System.Text.Json;
|
||||
using System.Threading.Tasks;
|
||||
using Auth.Contracts.DTOs.Auth;
|
||||
using Blazored.LocalStorage;
|
||||
using Microsoft.AspNetCore.Components.Authorization;
|
||||
|
||||
namespace Auth.RCL.Services
|
||||
{
|
||||
public class ApiAuthenticationStateProvider : AuthenticationStateProvider
|
||||
{
|
||||
private readonly HttpClient _httpClient;
|
||||
private readonly ILocalStorageService _localStorage;
|
||||
|
||||
public ApiAuthenticationStateProvider(
|
||||
HttpClient httpClient,
|
||||
ILocalStorageService localStorage
|
||||
)
|
||||
{
|
||||
_httpClient = httpClient;
|
||||
_localStorage = localStorage;
|
||||
}
|
||||
|
||||
public override async Task<AuthenticationState> GetAuthenticationStateAsync()
|
||||
{
|
||||
var refreshToken = await _localStorage.GetItemAsync<string>("refreshToken");
|
||||
var accessToken = await _localStorage.GetItemAsync<string>("authToken");
|
||||
var expiryDate = await _localStorage.GetItemAsync<string>("expiryDate");
|
||||
|
||||
if (string.IsNullOrWhiteSpace(accessToken))
|
||||
return new AuthenticationState(new ClaimsPrincipal(new ClaimsIdentity()));
|
||||
|
||||
if (DateTime.Now.AddMinutes(4) > DateTime.Parse(expiryDate))
|
||||
{
|
||||
var tokenModel = JsonSerializer.Serialize(
|
||||
new TokenModel()
|
||||
{
|
||||
RefreshToken = refreshToken,
|
||||
AccessToken = accessToken,
|
||||
Expiry = new DateTime(),
|
||||
}
|
||||
);
|
||||
var response = await _httpClient.PostAsync(
|
||||
"auth/refresh",
|
||||
new StringContent(tokenModel, Encoding.UTF8, "application/json")
|
||||
);
|
||||
|
||||
if (!response.IsSuccessStatusCode)
|
||||
{
|
||||
_httpClient.DefaultRequestHeaders.Authorization = null;
|
||||
MarkUserAsLoggedOut();
|
||||
return new AuthenticationState(new ClaimsPrincipal(new ClaimsIdentity()));
|
||||
}
|
||||
|
||||
var loginResult = JsonSerializer.Deserialize<LoginResult>(
|
||||
await response.Content.ReadAsStringAsync(),
|
||||
new JsonSerializerOptions { PropertyNameCaseInsensitive = true }
|
||||
);
|
||||
|
||||
await _localStorage.SetItemAsync("authToken", loginResult.AccessToken);
|
||||
await _localStorage.SetItemAsync("refreshToken", loginResult.RefreshToken);
|
||||
await _localStorage.SetItemAsync("expiryDate", loginResult.Expiry);
|
||||
|
||||
accessToken = loginResult.AccessToken;
|
||||
}
|
||||
|
||||
// if (string.IsNullOrWhiteSpace(savedToken) || DateTime.Now > DateTime.Parse(expiryDate))
|
||||
// {
|
||||
// return new AuthenticationState(new ClaimsPrincipal(new ClaimsIdentity()));
|
||||
// }
|
||||
|
||||
|
||||
_httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue(
|
||||
"Bearer",
|
||||
accessToken
|
||||
);
|
||||
|
||||
var claims = ParseClaimsFromJwt(accessToken);
|
||||
if (claims is null)
|
||||
return new AuthenticationState(new ClaimsPrincipal(new ClaimsIdentity()));
|
||||
|
||||
return new AuthenticationState(new ClaimsPrincipal(new ClaimsIdentity(claims, "jwt")));
|
||||
}
|
||||
|
||||
public async void MarkUserAsAuthenticated(string jwtToken)
|
||||
{
|
||||
var claims = ParseClaimsFromJwt(jwtToken);
|
||||
|
||||
var authenticatedUser = new ClaimsPrincipal(new ClaimsIdentity(claims, "apiauth"));
|
||||
var authState = Task.FromResult(new AuthenticationState(authenticatedUser));
|
||||
NotifyAuthenticationStateChanged(authState);
|
||||
|
||||
// var userId = authenticatedUser.Claims.FirstOrDefault(x => x.Type == "uid").Value;
|
||||
}
|
||||
|
||||
public async Task MarkUserAsLoggedOut()
|
||||
{
|
||||
var anonymousUser = new ClaimsPrincipal(new ClaimsIdentity());
|
||||
var authState = Task.FromResult(new AuthenticationState(anonymousUser));
|
||||
NotifyAuthenticationStateChanged(authState);
|
||||
|
||||
_httpClient.DefaultRequestHeaders.Authorization = null;
|
||||
}
|
||||
|
||||
private IEnumerable<Claim> ParseClaimsFromJwt(string jwt)
|
||||
{
|
||||
try
|
||||
{
|
||||
var claims = new List<Claim>();
|
||||
var payload = jwt.Split('.')[1];
|
||||
var jsonBytes = ParseBase64WithoutPadding(payload);
|
||||
var keyValuePairs = JsonSerializer.Deserialize<Dictionary<string, object>>(
|
||||
jsonBytes
|
||||
);
|
||||
|
||||
keyValuePairs.TryGetValue(ClaimTypes.Role, out object roles);
|
||||
|
||||
if (roles != null)
|
||||
{
|
||||
if (roles.ToString().Trim().StartsWith("["))
|
||||
{
|
||||
var parsedRoles = JsonSerializer.Deserialize<string[]>(roles.ToString());
|
||||
|
||||
foreach (var parsedRole in parsedRoles)
|
||||
{
|
||||
claims.Add(new Claim(ClaimTypes.Role, parsedRole));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
claims.Add(new Claim(ClaimTypes.Role, roles.ToString()));
|
||||
}
|
||||
|
||||
keyValuePairs.Remove(ClaimTypes.Role);
|
||||
}
|
||||
|
||||
claims.AddRange(
|
||||
keyValuePairs.Select(kvp => new Claim(kvp.Key, kvp.Value.ToString()))
|
||||
);
|
||||
|
||||
return claims;
|
||||
}
|
||||
catch
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private byte[] ParseBase64WithoutPadding(string base64)
|
||||
{
|
||||
switch (base64.Length % 4)
|
||||
{
|
||||
case 2:
|
||||
base64 += "==";
|
||||
break;
|
||||
case 3:
|
||||
base64 += "=";
|
||||
break;
|
||||
}
|
||||
return Convert.FromBase64String(base64);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user