hn-20-2/Apps/Client/JwtAuthStateProvider.cs
2021-04-29 15:44:39 +02:00

104 lines
3.0 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 Client
{
public class JwtAuthStateProvider : AuthenticationStateProvider
{
private readonly AccountsClient _accounts;
private readonly LocalStorage _storage;
private readonly HttpClient _http;
public JwtAuthStateProvider(AccountsClient accounts, LocalStorage storage, HttpClient http)
{
_accounts = accounts;
_storage = storage;
_http = http;
}
public override Task<AuthenticationState> GetAuthenticationStateAsync()
{
return AuthenticationStateFromCurrentToken();
}
public async Task TryLoginAsync(LoginViewModel cmd)
{
var token = await _accounts.LoginAsync(cmd);
await _storage.Save("token", token);
NotifyAuthenticationStateChanged(AuthenticationStateFromCurrentToken());
}
public async Task Logout()
{
await _storage.Save("token", string.Empty);
NotifyAuthenticationStateChanged(AuthenticationStateFromCurrentToken());
}
private async Task<AuthenticationState> AuthenticationStateFromCurrentToken()
{
var token = await _storage.Get("token");
if (string.IsNullOrWhiteSpace(token))
{
_http.DefaultRequestHeaders.Authorization = null;
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);
}
}
}