Switched to LocalStorage. Upgraded MoonCore. Improved auth flow

This commit is contained in:
Masu Baumgartner
2024-10-23 21:37:26 +02:00
parent 910f190c86
commit 6f3341e6ad
7 changed files with 76 additions and 89 deletions

View File

@@ -10,10 +10,10 @@
<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly" Version="8.0.6"/>
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.DevServer" Version="8.0.6" PrivateAssets="all"/>
<PackageReference Include="MoonCore" Version="1.6.4" />
<PackageReference Include="MoonCore.Blazor" Version="1.2.1" />
<PackageReference Include="MoonCore" Version="1.6.6" />
<PackageReference Include="MoonCore.Blazor" Version="1.2.4" />
<PackageReference Include="MoonCore.PluginFramework" Version="1.0.0" />
<PackageReference Include="MoonCore.Blazor.Tailwind" Version="1.0.6" />
<PackageReference Include="MoonCore.Blazor.Tailwind" Version="1.0.7" />
</ItemGroup>
<ItemGroup>

View File

@@ -1,12 +1,11 @@
using System.Net.Http.Headers;
using System.Net.Http.Json;
using System.Text.Json;
using Microsoft.AspNetCore.Components.Web;
using Microsoft.AspNetCore.Components.WebAssembly.Hosting;
using MoonCore.Blazor.Extensions;
using MoonCore.Blazor.Services;
using MoonCore.Blazor.Tailwind.Extensions;
using MoonCore.Blazor.Tailwind.Forms;
using MoonCore.Blazor.Tailwind.Forms.Components;
using MoonCore.Blazor.Tailwind.Services;
using MoonCore.Exceptions;
using MoonCore.Extensions;
using MoonCore.Helpers;
using MoonCore.Models;
@@ -55,42 +54,41 @@ builder.Logging.AddProviders(providers);
builder.RootComponents.Add<App>("#app");
builder.RootComponents.Add<HeadOutlet>("head::after");
builder.Services.AddScoped(sp => new HttpClient { BaseAddress = new Uri(builder.HostEnvironment.BaseAddress) });
builder.Services.AddScoped(_ => new HttpClient { BaseAddress = new Uri(builder.HostEnvironment.BaseAddress) });
builder.Services.AddScoped(sp =>
{
var httpClient = sp.GetRequiredService<HttpClient>();
var localStorageService = sp.GetRequiredService<LocalStorageService>();
var result = new HttpApiClient(httpClient);
result.UseBearerTokenConsumer(async () =>
result.AddLocalStorageTokenAuthentication(localStorageService, async refreshToken =>
{
var cookieService = sp.GetRequiredService<CookieService>();
try
{
var httpApiClient = new HttpApiClient(httpClient);
return new TokenConsumer(
await cookieService.GetValue("kms-access", "x"),
await cookieService.GetValue("kms-refresh", "x"),
DateTimeOffset.FromUnixTimeSeconds(long.Parse(await cookieService.GetValue("kms-timestamp", "0"))).UtcDateTime,
async refreshToken =>
{
var response = await httpClient.PostAsync("api/auth/refresh", new StringContent(
JsonSerializer.Serialize(new RefreshRequest()
{
RefreshToken = refreshToken
}), new MediaTypeHeaderValue("application/json")
));
var refreshRes = await response.ParseAsJson<RefreshResponse>();
await cookieService.SetValue("kms-access", refreshRes.AccessToken, 10);
await cookieService.SetValue("kms-refresh", refreshRes.RefreshToken, 10);
await cookieService.SetValue("kms-timestamp", DateTimeOffset.UtcNow.AddSeconds(60).ToUnixTimeSeconds().ToString(), 10);
return new TokenPair()
var response = await httpApiClient.PostJson<RefreshResponse>(
"api/auth/refresh",
new RefreshRequest()
{
AccessToken = await cookieService.GetValue("kms-access", "x"),
RefreshToken = await cookieService.GetValue("kms-refresh", "x")
};
}
);
RefreshToken = refreshToken
}
);
return (new TokenPair()
{
AccessToken = response.AccessToken,
RefreshToken = response.RefreshToken
}, response.ExpiresAt);
}
catch (HttpApiException)
{
return (new TokenPair()
{
AccessToken = "unset",
RefreshToken = "unset"
}, DateTime.MinValue);
}
});
return result;
@@ -98,6 +96,7 @@ builder.Services.AddScoped(sp =>
builder.Services.AddMoonCoreBlazorTailwind();
builder.Services.AddScoped<WindowService>();
builder.Services.AddScoped<LocalStorageService>();
builder.Services.AutoAddServices<Program>();

View File

@@ -1,7 +1,10 @@
using MoonCore.Attributes;
using MoonCore.Blazor.Services;
using MoonCore.Blazor.Tailwind.Services;
using MoonCore.Exceptions;
using MoonCore.Helpers;
using MoonCore.Models;
using Moonlight.Shared.Http.Requests.Auth;
using Moonlight.Shared.Http.Responses.Auth;
namespace Moonlight.Client.Services;
@@ -14,24 +17,20 @@ public class IdentityService
public string[] Permissions { get; private set; }
public bool IsLoggedIn { get; private set; }
public event Func<Task> OnStateChanged;
private readonly HttpApiClient HttpApiClient;
private readonly LocalStorageService LocalStorageService;
private readonly CookieService CookieService;
private readonly HttpApiClient ApiClient;
public IdentityService(CookieService cookieService, HttpApiClient apiClient)
public IdentityService(HttpApiClient httpApiClient, LocalStorageService localStorageService)
{
CookieService = cookieService;
ApiClient = apiClient;
HttpApiClient = httpApiClient;
LocalStorageService = localStorageService;
}
#region Login / Logout
public async Task Check()
{
try
{
var response = await ApiClient.GetJson<CheckResponse>("api/auth/check");
var response = await HttpApiClient.GetJson<CheckResponse>("api/auth/check");
Username = response.Username;
Email = response.Email;
@@ -47,19 +46,12 @@ public class IdentityService
//await OnStateChanged?.Invoke();
}
public async Task Login(string token)
{
await CookieService.SetValue("token", token, 30);
await Check();
}
public async Task Logout()
{
await CookieService.SetValue("token", "", 30);
await Check();
await LocalStorageService.SetString("AccessToken", "unset");
await LocalStorageService.SetString("RefreshToken", "unset");
await LocalStorageService.Set("ExpiresAt", DateTime.MinValue);
}
#endregion
public bool HasPermission(string requiredPermission)
{

View File

@@ -3,6 +3,7 @@
@inject IdentityService IdentityService
@inject ToastService ToastService
@inject NavigationManager Navigation
<div class="sticky top-0 z-40 flex h-16 shrink-0 items-center gap-x-4 bg-gray-800/60 backdrop-blur px-4 shadow-sm sm:gap-x-6 sm:px-6 lg:px-8">
@if (Layout.ShowMobileNavigation)
@@ -112,6 +113,7 @@
await IdentityService.Logout();
await ToastService.Info("Successfully logged out");
await Layout.Load();
//await Layout.Load();
Navigation.NavigateTo(Navigation.Uri, true);
}
}

View File

@@ -1,5 +1,6 @@
@page "/auth"
@using MoonCore.Blazor.Services
@using MoonCore.Helpers
@using Moonlight.Client.Services
@using Moonlight.Shared.Http.Requests.Auth
@@ -7,9 +8,9 @@
@inject NavigationManager Navigation
@inject HttpApiClient HttpApiClient
@inject CookieService CookieService
@inject WindowService WindowService
@inject HttpClient HttpClient
@inject LocalStorageService LocalStorageService
@if (Code == null)
{
@@ -95,9 +96,9 @@ else
Code = Code
});
await CookieService.SetValue("kms-access", authHandleData.AccessToken, 10);
await CookieService.SetValue("kms-refresh", authHandleData.RefreshToken, 10);
await CookieService.SetValue("kms-timestamp", DateTimeOffset.UtcNow.AddSeconds(60).ToUnixTimeSeconds().ToString(), 10);
await LocalStorageService.SetString("AccessToken", authHandleData.AccessToken);
await LocalStorageService.SetString("RefreshToken", authHandleData.RefreshToken);
await LocalStorageService.Set("ExpiresAt", authHandleData.ExpiresAt);
try
{
@@ -124,8 +125,8 @@ else
await WindowService.Open(
uri,
"OAuth2 Flow",
500,
650
600,
450
);
IsAuthenticating = true;
@@ -139,17 +140,23 @@ else
try
{
if(!await LocalStorageService.ContainsKey("AccessToken"))
continue;
if (HttpClient.DefaultRequestHeaders.Contains("Authorization"))
HttpClient.DefaultRequestHeaders.Remove("Authorization");
HttpClient.DefaultRequestHeaders.Add("Authorization", "Bearer " + await CookieService.GetValue("kms-access", "x"));
HttpClient.DefaultRequestHeaders.Add("Authorization", "Bearer " + await LocalStorageService.GetString("AccessToken"));
var res = await HttpClient.GetAsync("api/auth/check");
if(res.IsSuccessStatusCode)
if (res.IsSuccessStatusCode)
break;
}
finally{}
catch (Exception e)
{
Console.WriteLine(e);
}
}
Navigation.NavigateTo(Navigation.Uri, true);

View File

@@ -1,25 +1,11 @@
window.moonlight = {
window: {
open: function (url, title, w, h) {
// Fixes dual-screen position Most browsers Firefox
const dualScreenLeft = window.screenLeft !== undefined ? window.screenLeft : window.screenX;
const dualScreenTop = window.screenTop !== undefined ? window.screenTop : window.screenY;
const width = window.innerWidth ? window.innerWidth : document.documentElement.clientWidth ? document.documentElement.clientWidth : screen.width;
const height = window.innerHeight ? window.innerHeight : document.documentElement.clientHeight ? document.documentElement.clientHeight : screen.height;
const systemZoom = width / window.screen.availWidth;
const left = (width - w) / 2 / systemZoom + dualScreenLeft
const top = (height - h) / 2 / systemZoom + dualScreenTop
const newWindow = window.open(url, title,
`
scrollbars=yes,
width=${w / systemZoom},
height=${h / systemZoom},
top=${top},
left=${left}
`
)
let height = w;
let width = h;
var left = (screen.width - width) / 2;
var top = (screen.height - height) / 2;
var newWindow = window.open(url, title, 'resizable = yes, width=' + width + ', height=' + height + ', top=' + top + ', left=' + left);
if (window.focus) newWindow.focus();
},