feat(backend): start authentication controllers

This commit is contained in:
sam 2024-06-12 03:47:20 +02:00
parent 493a6e4d29
commit 25540f2de2
15 changed files with 777 additions and 17 deletions

View file

@ -0,0 +1,38 @@
using System.Web;
using Foxnouns.Backend.Services;
using Microsoft.AspNetCore.Mvc;
using NodaTime;
namespace Foxnouns.Backend.Controllers.Authentication;
[Route("/api/v2/auth")]
public class AuthController(Config config, KeyCacheService keyCacheSvc) : ApiControllerBase
{
[HttpPost("urls")]
[ProducesResponseType(StatusCodes.Status200OK, Type = typeof(UrlsResponse))]
public async Task<IActionResult> UrlsAsync()
{
var state = HttpUtility.UrlEncode(await keyCacheSvc.GenerateAuthStateAsync());
string? discord = null;
if (config.DiscordAuth.ClientId != null && config.DiscordAuth.ClientSecret != null)
discord =
$"https://discord.com/oauth2/authorize?response_type=code" +
$"&client_id={config.DiscordAuth.ClientId}&scope=identify" +
$"&prompt=none&state={state}" +
$"&redirect_uri={HttpUtility.UrlEncode($"{config.BaseUrl}/auth/login/discord")}";
return Ok(new UrlsResponse(discord, null, null));
}
private record UrlsResponse(
string? Discord,
string? Google,
string? Tumblr
);
internal record AuthResponse(
UserRendererService.UserResponse User,
string Token,
Instant ExpiresAt
);
}

View file

@ -6,9 +6,11 @@ namespace Foxnouns.Backend.Controllers.Authentication;
[Route("/api/v2/auth/discord")]
public class DiscordAuthController(Config config, DatabaseContext db) : ApiControllerBase
{
[HttpPost("url")]
public async Task<IActionResult> AuthenticationUrl()
private void CheckRequirements()
{
throw new NotImplementedException();
if (config.DiscordAuth.ClientId == null || config.DiscordAuth.ClientSecret == null)
{
throw new ApiError.BadRequest("Discord authentication is not enabled on this instance.");
}
}
}

View file

@ -0,0 +1,31 @@
using Foxnouns.Backend.Database;
using Foxnouns.Backend.Services;
using Microsoft.AspNetCore.Mvc;
using NodaTime;
namespace Foxnouns.Backend.Controllers.Authentication;
[Route("/api/v2/auth/email")]
public class EmailAuthController(DatabaseContext db, AuthService authSvc, UserRendererService userRendererSvc, IClock clock, ILogger logger) : ApiControllerBase
{
[HttpPost("login")]
public async Task<IActionResult> LoginAsync([FromBody] LoginRequest req)
{
var user = await authSvc.AuthenticateUserAsync(req.Email, req.Password);
var frontendApp = await db.GetFrontendApplicationAsync();
var (tokenStr, token) =
authSvc.GenerateToken(user, frontendApp, ["*"], clock.GetCurrentInstant() + Duration.FromDays(365));
db.Add(token);
await db.SaveChangesAsync();
return Ok(new AuthController.AuthResponse(
await userRendererSvc.RenderUserAsync(user, selfUser: user, renderMembers: false),
tokenStr,
token.ExpiresAt
));
}
public record LoginRequest(string Email, string Password);
}

View file

@ -10,7 +10,7 @@ public class DebugController(DatabaseContext db, AuthService authSvc, IClock clo
{
[HttpPost("users")]
[ProducesResponseType(StatusCodes.Status200OK, Type = typeof(AuthResponse))]
public async Task<IActionResult> CreateUser([FromBody] CreateUserRequest req)
public async Task<IActionResult> CreateUserAsync([FromBody] CreateUserRequest req)
{
logger.Debug("Creating user with username {Username} and email {Email}", req.Username, req.Email);