From c806c5d1394cb1a68710e665003f554af4295ab7 Mon Sep 17 00:00:00 2001 From: LittleSheep Date: Mon, 16 Jun 2025 00:12:19 +0800 Subject: [PATCH] :sparkles: Self-contained oidc receiver page --- .../Auth/OpenId/ConnectionController.cs | 4 +- .../Auth/OpenId/OidcService.cs | 33 +++++++----- DysonNetwork.Sphere/Pages/Auth/Token.cshtml | 50 +++++++++++++++++++ .../Pages/Auth/Token.cshtml.cs | 11 ++++ 4 files changed, 84 insertions(+), 14 deletions(-) create mode 100644 DysonNetwork.Sphere/Pages/Auth/Token.cshtml create mode 100644 DysonNetwork.Sphere/Pages/Auth/Token.cshtml.cs diff --git a/DysonNetwork.Sphere/Auth/OpenId/ConnectionController.cs b/DysonNetwork.Sphere/Auth/OpenId/ConnectionController.cs index 423b625..ea006fd 100644 --- a/DysonNetwork.Sphere/Auth/OpenId/ConnectionController.cs +++ b/DysonNetwork.Sphere/Auth/OpenId/ConnectionController.cs @@ -205,7 +205,7 @@ public class ConnectionController( // Login existing user var session = await auth.CreateSessionAsync(connection.Account, clock.GetCurrentInstant()); var token = auth.CreateToken(session); - return Redirect($"/?token={token}"); + return Redirect($"/auth/token?token={token}"); } // Register new user @@ -228,7 +228,7 @@ public class ConnectionController( var loginSession = await auth.CreateSessionAsync(account, clock.GetCurrentInstant()); var loginToken = auth.CreateToken(loginSession); - return Redirect($"/?token={loginToken}"); + return Redirect($"/auth/token?token={loginToken}"); } private static async Task ExtractCallbackData(HttpRequest request) diff --git a/DysonNetwork.Sphere/Auth/OpenId/OidcService.cs b/DysonNetwork.Sphere/Auth/OpenId/OidcService.cs index f2f53a1..2b058f3 100644 --- a/DysonNetwork.Sphere/Auth/OpenId/OidcService.cs +++ b/DysonNetwork.Sphere/Auth/OpenId/OidcService.cs @@ -11,9 +11,18 @@ namespace DysonNetwork.Sphere.Auth.OpenId; /// /// Base service for OpenID Connect authentication providers /// -public abstract class OidcService(IConfiguration configuration, IHttpClientFactory httpClientFactory, AppDatabase db) +public abstract class OidcService { - protected readonly IHttpClientFactory _httpClientFactory = httpClientFactory; + protected readonly IConfiguration _configuration; + protected readonly IHttpClientFactory _httpClientFactory; + protected readonly AppDatabase _db; + + protected OidcService(IConfiguration configuration, IHttpClientFactory httpClientFactory, AppDatabase db) + { + _configuration = configuration; + _httpClientFactory = httpClientFactory; + _db = db; + } /// /// Gets the unique identifier for this provider @@ -47,9 +56,9 @@ public abstract class OidcService(IConfiguration configuration, IHttpClientFacto { return new ProviderConfiguration { - ClientId = configuration[$"Oidc:{ConfigSectionName}:ClientId"] ?? "", - ClientSecret = configuration[$"Oidc:{ConfigSectionName}:ClientSecret"] ?? "", - RedirectUri = configuration["BaseUrl"] + "/auth/callback/" + ProviderName + ClientId = _configuration[$"Oidc:{ConfigSectionName}:ClientId"] ?? "", + ClientSecret = _configuration[$"Oidc:{ConfigSectionName}:ClientSecret"] ?? "", + RedirectUri = _configuration["BaseUrl"] + "/auth/callback/" + ProviderName }; } @@ -58,7 +67,7 @@ public abstract class OidcService(IConfiguration configuration, IHttpClientFacto /// protected async Task GetDiscoveryDocumentAsync() { - var client = httpClientFactory.CreateClient(); + var client = _httpClientFactory.CreateClient(); var response = await client.GetAsync(DiscoveryEndpoint); response.EnsureSuccessStatusCode(); return await response.Content.ReadFromJsonAsync(); @@ -78,7 +87,7 @@ public abstract class OidcService(IConfiguration configuration, IHttpClientFacto throw new InvalidOperationException("Token endpoint not found in discovery document"); } - var client = httpClientFactory.CreateClient(); + var client = _httpClientFactory.CreateClient(); var content = new FormUrlEncodedContent(BuildTokenRequestParameters(code, config, codeVerifier)); var response = await client.PostAsync(discoveryDocument.TokenEndpoint, content); @@ -169,7 +178,7 @@ public abstract class OidcService(IConfiguration configuration, IHttpClientFacto ) { // Create or update the account connection - var connection = await db.AccountConnections + var connection = await _db.AccountConnections .FirstOrDefaultAsync(c => c.Provider == ProviderName && c.ProvidedIdentifier == userInfo.UserId && c.AccountId == account.Id @@ -186,7 +195,7 @@ public abstract class OidcService(IConfiguration configuration, IHttpClientFacto LastUsedAt = SystemClock.Instance.GetCurrentInstant(), AccountId = account.Id }; - await db.AccountConnections.AddAsync(connection); + await _db.AccountConnections.AddAsync(connection); } // Create a challenge that's already completed @@ -206,7 +215,7 @@ public abstract class OidcService(IConfiguration configuration, IHttpClientFacto UserAgent = request.Request.Headers.UserAgent, }; - await db.AuthChallenges.AddAsync(challenge); + await _db.AuthChallenges.AddAsync(challenge); // Create a session var session = new Session @@ -217,8 +226,8 @@ public abstract class OidcService(IConfiguration configuration, IHttpClientFacto Challenge = challenge }; - await db.AuthSessions.AddAsync(session); - await db.SaveChangesAsync(); + await _db.AuthSessions.AddAsync(session); + await _db.SaveChangesAsync(); return session; } diff --git a/DysonNetwork.Sphere/Pages/Auth/Token.cshtml b/DysonNetwork.Sphere/Pages/Auth/Token.cshtml new file mode 100644 index 0000000..cefeaa7 --- /dev/null +++ b/DysonNetwork.Sphere/Pages/Auth/Token.cshtml @@ -0,0 +1,50 @@ +@page "/auth/token" +@model DysonNetwork.Sphere.Pages.Auth.TokenModel +@{ + ViewData["Title"] = "Authentication Successful"; + Layout = "_Layout"; +} + +
+
+

Authentication Successful

+

You can now close this window and return to the application.

+
+
+ +@section Scripts { + +} diff --git a/DysonNetwork.Sphere/Pages/Auth/Token.cshtml.cs b/DysonNetwork.Sphere/Pages/Auth/Token.cshtml.cs new file mode 100644 index 0000000..fdd6e87 --- /dev/null +++ b/DysonNetwork.Sphere/Pages/Auth/Token.cshtml.cs @@ -0,0 +1,11 @@ +using Microsoft.AspNetCore.Mvc.RazorPages; + +namespace DysonNetwork.Sphere.Pages.Auth +{ + public class TokenModel : PageModel + { + public void OnGet() + { + } + } +}