100 lines
2.8 KiB
C#
100 lines
2.8 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using System.Net.Http;
|
|
using System.Net.Http.Headers;
|
|
using System.Security.Claims;
|
|
using System.Text.Json;
|
|
using System.Threading.Tasks;
|
|
using Microsoft.AspNetCore.Components.Authorization;
|
|
|
|
namespace BlazorClient
|
|
{
|
|
public class JwtAuthStateProvider : AuthenticationStateProvider
|
|
{
|
|
private readonly HttpClient _http;
|
|
private readonly LocalStorage _storage;
|
|
|
|
public JwtAuthStateProvider(HttpClient http, LocalStorage storage)
|
|
{
|
|
_http = http;
|
|
_storage = storage;
|
|
}
|
|
|
|
public override Task<AuthenticationState> GetAuthenticationStateAsync()
|
|
{
|
|
return AuthenticationStateFromCurrentToken();
|
|
}
|
|
|
|
public async Task MarkUserAsAuthenticated(string token)
|
|
{
|
|
await _storage.Save("token", token);
|
|
NotifyAuthenticationStateChanged(AuthenticationStateFromCurrentToken());
|
|
}
|
|
|
|
public async Task LogoutCurrentUser()
|
|
{
|
|
await _storage.Save("token", string.Empty);
|
|
NotifyAuthenticationStateChanged(AuthenticationStateFromCurrentToken());
|
|
}
|
|
|
|
private async Task<AuthenticationState> AuthenticationStateFromCurrentToken()
|
|
{
|
|
var token = await _storage.Get("token");
|
|
|
|
if (string.IsNullOrWhiteSpace(token))
|
|
{
|
|
return new AuthenticationState(new ClaimsPrincipal(new ClaimsIdentity()));
|
|
}
|
|
|
|
_http.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token);
|
|
|
|
var claims = ParseClaimsFromJwt(token);
|
|
var principal = new ClaimsPrincipal(
|
|
new ClaimsIdentity(claims, "jwt", "unique_name", null));
|
|
return new AuthenticationState(principal);
|
|
}
|
|
|
|
private IEnumerable<Claim> ParseClaimsFromJwt(string jwt)
|
|
{
|
|
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;
|
|
}
|
|
|
|
private byte[] ParseBase64WithoutPadding(string base64)
|
|
{
|
|
switch (base64.Length % 4)
|
|
{
|
|
case 2: base64 += "=="; break;
|
|
case 3: base64 += "="; break;
|
|
}
|
|
return Convert.FromBase64String(base64);
|
|
}
|
|
}
|
|
} |