Switched to LocalStorage. Upgraded MoonCore. Improved auth flow
This commit is contained in:
@@ -12,13 +12,14 @@
|
|||||||
<PrivateAssets>all</PrivateAssets>
|
<PrivateAssets>all</PrivateAssets>
|
||||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||||
</PackageReference>
|
</PackageReference>
|
||||||
<PackageReference Include="MoonCore" Version="1.6.4" />
|
<PackageReference Include="MoonCore" Version="1.6.6" />
|
||||||
|
<PackageReference Include="MoonCore.Blazor" Version="1.2.4" />
|
||||||
|
<PackageReference Include="MoonCore.Blazor.Tailwind" Version="1.0.7" />
|
||||||
<PackageReference Include="MoonCore.Extended" Version="1.1.2" />
|
<PackageReference Include="MoonCore.Extended" Version="1.1.2" />
|
||||||
<PackageReference Include="MoonCore.PluginFramework" Version="1.0.0" />
|
<PackageReference Include="MoonCore.PluginFramework" Version="1.0.0" />
|
||||||
<PackageReference Include="Pomelo.EntityFrameworkCore.MySql" Version="8.0.2" />
|
<PackageReference Include="Pomelo.EntityFrameworkCore.MySql" Version="8.0.2" />
|
||||||
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.4.0"/>
|
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.4.0"/>
|
||||||
<PackageReference Include="Ben.Demystifier" Version="0.4.1" />
|
<PackageReference Include="Ben.Demystifier" Version="0.4.1" />
|
||||||
<PackageReference Include="MoonCore.Blazor.Tailwind" Version="1.0.6" />
|
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
|||||||
@@ -10,10 +10,10 @@
|
|||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly" Version="8.0.6"/>
|
<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="Microsoft.AspNetCore.Components.WebAssembly.DevServer" Version="8.0.6" PrivateAssets="all"/>
|
||||||
<PackageReference Include="MoonCore" Version="1.6.4" />
|
<PackageReference Include="MoonCore" Version="1.6.6" />
|
||||||
<PackageReference Include="MoonCore.Blazor" Version="1.2.1" />
|
<PackageReference Include="MoonCore.Blazor" Version="1.2.4" />
|
||||||
<PackageReference Include="MoonCore.PluginFramework" Version="1.0.0" />
|
<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>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
|||||||
@@ -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.Web;
|
||||||
using Microsoft.AspNetCore.Components.WebAssembly.Hosting;
|
using Microsoft.AspNetCore.Components.WebAssembly.Hosting;
|
||||||
|
using MoonCore.Blazor.Extensions;
|
||||||
|
using MoonCore.Blazor.Services;
|
||||||
using MoonCore.Blazor.Tailwind.Extensions;
|
using MoonCore.Blazor.Tailwind.Extensions;
|
||||||
using MoonCore.Blazor.Tailwind.Forms;
|
using MoonCore.Blazor.Tailwind.Forms;
|
||||||
using MoonCore.Blazor.Tailwind.Forms.Components;
|
using MoonCore.Blazor.Tailwind.Forms.Components;
|
||||||
using MoonCore.Blazor.Tailwind.Services;
|
using MoonCore.Exceptions;
|
||||||
using MoonCore.Extensions;
|
using MoonCore.Extensions;
|
||||||
using MoonCore.Helpers;
|
using MoonCore.Helpers;
|
||||||
using MoonCore.Models;
|
using MoonCore.Models;
|
||||||
@@ -55,42 +54,41 @@ builder.Logging.AddProviders(providers);
|
|||||||
builder.RootComponents.Add<App>("#app");
|
builder.RootComponents.Add<App>("#app");
|
||||||
builder.RootComponents.Add<HeadOutlet>("head::after");
|
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 =>
|
builder.Services.AddScoped(sp =>
|
||||||
{
|
{
|
||||||
var httpClient = sp.GetRequiredService<HttpClient>();
|
var httpClient = sp.GetRequiredService<HttpClient>();
|
||||||
|
var localStorageService = sp.GetRequiredService<LocalStorageService>();
|
||||||
var result = new HttpApiClient(httpClient);
|
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(
|
var response = await httpApiClient.PostJson<RefreshResponse>(
|
||||||
await cookieService.GetValue("kms-access", "x"),
|
"api/auth/refresh",
|
||||||
await cookieService.GetValue("kms-refresh", "x"),
|
new RefreshRequest()
|
||||||
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
|
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()
|
|
||||||
{
|
|
||||||
AccessToken = await cookieService.GetValue("kms-access", "x"),
|
|
||||||
RefreshToken = await cookieService.GetValue("kms-refresh", "x")
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
return (new TokenPair()
|
||||||
|
{
|
||||||
|
AccessToken = response.AccessToken,
|
||||||
|
RefreshToken = response.RefreshToken
|
||||||
|
}, response.ExpiresAt);
|
||||||
|
}
|
||||||
|
catch (HttpApiException)
|
||||||
|
{
|
||||||
|
return (new TokenPair()
|
||||||
|
{
|
||||||
|
AccessToken = "unset",
|
||||||
|
RefreshToken = "unset"
|
||||||
|
}, DateTime.MinValue);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
@@ -98,6 +96,7 @@ builder.Services.AddScoped(sp =>
|
|||||||
|
|
||||||
builder.Services.AddMoonCoreBlazorTailwind();
|
builder.Services.AddMoonCoreBlazorTailwind();
|
||||||
builder.Services.AddScoped<WindowService>();
|
builder.Services.AddScoped<WindowService>();
|
||||||
|
builder.Services.AddScoped<LocalStorageService>();
|
||||||
|
|
||||||
builder.Services.AutoAddServices<Program>();
|
builder.Services.AutoAddServices<Program>();
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,10 @@
|
|||||||
using MoonCore.Attributes;
|
using MoonCore.Attributes;
|
||||||
|
using MoonCore.Blazor.Services;
|
||||||
using MoonCore.Blazor.Tailwind.Services;
|
using MoonCore.Blazor.Tailwind.Services;
|
||||||
using MoonCore.Exceptions;
|
using MoonCore.Exceptions;
|
||||||
using MoonCore.Helpers;
|
using MoonCore.Helpers;
|
||||||
|
using MoonCore.Models;
|
||||||
|
using Moonlight.Shared.Http.Requests.Auth;
|
||||||
using Moonlight.Shared.Http.Responses.Auth;
|
using Moonlight.Shared.Http.Responses.Auth;
|
||||||
|
|
||||||
namespace Moonlight.Client.Services;
|
namespace Moonlight.Client.Services;
|
||||||
@@ -14,24 +17,20 @@ public class IdentityService
|
|||||||
public string[] Permissions { get; private set; }
|
public string[] Permissions { get; private set; }
|
||||||
public bool IsLoggedIn { 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;
|
public IdentityService(HttpApiClient httpApiClient, LocalStorageService localStorageService)
|
||||||
private readonly HttpApiClient ApiClient;
|
|
||||||
|
|
||||||
public IdentityService(CookieService cookieService, HttpApiClient apiClient)
|
|
||||||
{
|
{
|
||||||
CookieService = cookieService;
|
HttpApiClient = httpApiClient;
|
||||||
ApiClient = apiClient;
|
LocalStorageService = localStorageService;
|
||||||
}
|
}
|
||||||
|
|
||||||
#region Login / Logout
|
|
||||||
|
|
||||||
public async Task Check()
|
public async Task Check()
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var response = await ApiClient.GetJson<CheckResponse>("api/auth/check");
|
var response = await HttpApiClient.GetJson<CheckResponse>("api/auth/check");
|
||||||
|
|
||||||
Username = response.Username;
|
Username = response.Username;
|
||||||
Email = response.Email;
|
Email = response.Email;
|
||||||
@@ -47,20 +46,13 @@ public class IdentityService
|
|||||||
//await OnStateChanged?.Invoke();
|
//await OnStateChanged?.Invoke();
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task Login(string token)
|
|
||||||
{
|
|
||||||
await CookieService.SetValue("token", token, 30);
|
|
||||||
await Check();
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task Logout()
|
public async Task Logout()
|
||||||
{
|
{
|
||||||
await CookieService.SetValue("token", "", 30);
|
await LocalStorageService.SetString("AccessToken", "unset");
|
||||||
await Check();
|
await LocalStorageService.SetString("RefreshToken", "unset");
|
||||||
|
await LocalStorageService.Set("ExpiresAt", DateTime.MinValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
public bool HasPermission(string requiredPermission)
|
public bool HasPermission(string requiredPermission)
|
||||||
{
|
{
|
||||||
// Check for wildcard permission
|
// Check for wildcard permission
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
|
|
||||||
@inject IdentityService IdentityService
|
@inject IdentityService IdentityService
|
||||||
@inject ToastService ToastService
|
@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">
|
<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)
|
@if (Layout.ShowMobileNavigation)
|
||||||
@@ -112,6 +113,7 @@
|
|||||||
await IdentityService.Logout();
|
await IdentityService.Logout();
|
||||||
await ToastService.Info("Successfully logged out");
|
await ToastService.Info("Successfully logged out");
|
||||||
|
|
||||||
await Layout.Load();
|
//await Layout.Load();
|
||||||
|
Navigation.NavigateTo(Navigation.Uri, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
@page "/auth"
|
@page "/auth"
|
||||||
|
|
||||||
|
@using MoonCore.Blazor.Services
|
||||||
@using MoonCore.Helpers
|
@using MoonCore.Helpers
|
||||||
@using Moonlight.Client.Services
|
@using Moonlight.Client.Services
|
||||||
@using Moonlight.Shared.Http.Requests.Auth
|
@using Moonlight.Shared.Http.Requests.Auth
|
||||||
@@ -7,9 +8,9 @@
|
|||||||
|
|
||||||
@inject NavigationManager Navigation
|
@inject NavigationManager Navigation
|
||||||
@inject HttpApiClient HttpApiClient
|
@inject HttpApiClient HttpApiClient
|
||||||
@inject CookieService CookieService
|
|
||||||
@inject WindowService WindowService
|
@inject WindowService WindowService
|
||||||
@inject HttpClient HttpClient
|
@inject HttpClient HttpClient
|
||||||
|
@inject LocalStorageService LocalStorageService
|
||||||
|
|
||||||
@if (Code == null)
|
@if (Code == null)
|
||||||
{
|
{
|
||||||
@@ -95,9 +96,9 @@ else
|
|||||||
Code = Code
|
Code = Code
|
||||||
});
|
});
|
||||||
|
|
||||||
await CookieService.SetValue("kms-access", authHandleData.AccessToken, 10);
|
await LocalStorageService.SetString("AccessToken", authHandleData.AccessToken);
|
||||||
await CookieService.SetValue("kms-refresh", authHandleData.RefreshToken, 10);
|
await LocalStorageService.SetString("RefreshToken", authHandleData.RefreshToken);
|
||||||
await CookieService.SetValue("kms-timestamp", DateTimeOffset.UtcNow.AddSeconds(60).ToUnixTimeSeconds().ToString(), 10);
|
await LocalStorageService.Set("ExpiresAt", authHandleData.ExpiresAt);
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@@ -124,8 +125,8 @@ else
|
|||||||
await WindowService.Open(
|
await WindowService.Open(
|
||||||
uri,
|
uri,
|
||||||
"OAuth2 Flow",
|
"OAuth2 Flow",
|
||||||
500,
|
600,
|
||||||
650
|
450
|
||||||
);
|
);
|
||||||
|
|
||||||
IsAuthenticating = true;
|
IsAuthenticating = true;
|
||||||
@@ -139,17 +140,23 @@ else
|
|||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
if(!await LocalStorageService.ContainsKey("AccessToken"))
|
||||||
|
continue;
|
||||||
|
|
||||||
if (HttpClient.DefaultRequestHeaders.Contains("Authorization"))
|
if (HttpClient.DefaultRequestHeaders.Contains("Authorization"))
|
||||||
HttpClient.DefaultRequestHeaders.Remove("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");
|
var res = await HttpClient.GetAsync("api/auth/check");
|
||||||
|
|
||||||
if (res.IsSuccessStatusCode)
|
if (res.IsSuccessStatusCode)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
finally{}
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
Console.WriteLine(e);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Navigation.NavigateTo(Navigation.Uri, true);
|
Navigation.NavigateTo(Navigation.Uri, true);
|
||||||
|
|||||||
@@ -1,25 +1,11 @@
|
|||||||
window.moonlight = {
|
window.moonlight = {
|
||||||
window: {
|
window: {
|
||||||
open: function (url, title, w, h) {
|
open: function (url, title, w, h) {
|
||||||
// Fixes dual-screen position Most browsers Firefox
|
let height = w;
|
||||||
const dualScreenLeft = window.screenLeft !== undefined ? window.screenLeft : window.screenX;
|
let width = h;
|
||||||
const dualScreenTop = window.screenTop !== undefined ? window.screenTop : window.screenY;
|
var left = (screen.width - width) / 2;
|
||||||
|
var top = (screen.height - height) / 2;
|
||||||
const width = window.innerWidth ? window.innerWidth : document.documentElement.clientWidth ? document.documentElement.clientWidth : screen.width;
|
var newWindow = window.open(url, title, 'resizable = yes, width=' + width + ', height=' + height + ', top=' + top + ', left=' + left);
|
||||||
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}
|
|
||||||
`
|
|
||||||
)
|
|
||||||
|
|
||||||
if (window.focus) newWindow.focus();
|
if (window.focus) newWindow.focus();
|
||||||
},
|
},
|
||||||
|
|||||||
Reference in New Issue
Block a user