mirror of
https://github.com/DorkSquadRR/DorkNet.git
synced 2026-10-25 23:18:44 -07:00
feat(auth): external sign-in for the website and admin panel
Players sign in to the website, and admins to the admin panel, with an OpenID Connect provider (DorkNet:SignIn:*). The first sign-in links the provider identity (issuer + subject) to a DorkNet account with that account's password; after that the provider sign-in is enough. - Cookie sessions per host, keys persisted in the database so redeploys keep people signed in; unlink, deletion or a ban ends the session. - Link attempts limited to 5 failures per 15 minutes per identity and per username. - Admin panel: "Sign in with ..." exchanges the session for the usual admin tokens via GET /api/admin/v1/sso (IsAdmin still required). - Downloads: optional DorkNet:Downloads:RequireSignIn serves the manifest and files only to signed-in players; the Downloads and Quest pages offer sign-in instead. - Website: sign-in in the header, /link and /account pages. The game client's login is unchanged.
This commit is contained in:
@@ -1,3 +1,4 @@
|
||||
using Microsoft.AspNetCore.Authentication;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using DorkNet.Server.Data;
|
||||
@@ -41,6 +42,27 @@ public class AdminLoginController(
|
||||
if (!player.IsAdmin)
|
||||
return StatusCode(403, new { error = "not_admin" });
|
||||
|
||||
return TokenResponse(player);
|
||||
}
|
||||
|
||||
/// <summary>GET api/admin/v1/sso — exchange a single sign-on session
|
||||
/// (<see cref="ExternalSignIn.WebScheme"/>, signed in on this admin host via
|
||||
/// the external provider) for the same token pair <c>login</c> returns.
|
||||
/// Admin rights still come from the account's <c>IsAdmin</c>.</summary>
|
||||
[HttpGet("sso")]
|
||||
public async Task<ActionResult> Sso()
|
||||
{
|
||||
var web = await HttpContext.AuthenticateAsync(ExternalSignIn.WebScheme);
|
||||
if (!web.Succeeded || ExternalSignIn.PlayerId(web.Principal) is not { } playerId)
|
||||
return Unauthorized(new { error = "not_signed_in" });
|
||||
var player = await db.Players.FirstOrDefaultAsync(p => p.Id == playerId);
|
||||
if (player is null) return Unauthorized(new { error = "not_signed_in" });
|
||||
if (!player.IsAdmin) return StatusCode(403, new { error = "not_admin" });
|
||||
return TokenResponse(player);
|
||||
}
|
||||
|
||||
private OkObjectResult TokenResponse(Data.Entities.PlayerEntity player)
|
||||
{
|
||||
var (access, refresh) = authService.GenerateTokenPair(player.Id);
|
||||
return Ok(new
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user