84 lines
2.9 KiB
C#
84 lines
2.9 KiB
C#
using Htmx.ApiDemo.Data;
|
|
using Immediate.Apis.Shared;
|
|
using Immediate.Handlers.Shared;
|
|
using Microsoft.AspNetCore.Antiforgery;
|
|
using Microsoft.AspNetCore.Http;
|
|
using Microsoft.AspNetCore.Mvc;
|
|
|
|
namespace Htmx.ApiDemo.Templates;
|
|
|
|
public sealed class Login : LoginBase
|
|
{
|
|
private readonly byte[] _errorData;
|
|
private readonly byte[] _afTokenData;
|
|
|
|
public Login(string? errorMessage = null, string? afToken = null)
|
|
{
|
|
_errorData = string.IsNullOrEmpty(errorMessage)
|
|
? []
|
|
: $"""<div class="rounded-md bg-destructive/15 px-4 py-3 text-sm text-destructive border border-destructive/30">{System.Web.HttpUtility.HtmlEncode(errorMessage)}</div>""".ToUtf8Bytes();
|
|
|
|
_afTokenData = string.IsNullOrEmpty(afToken)
|
|
? []
|
|
: $"""<input type="hidden" name="__RequestVerificationToken" value="{System.Web.HttpUtility.HtmlAttributeEncode(afToken)}" />""".ToUtf8Bytes();
|
|
}
|
|
|
|
protected override void RenderErrorMessage(HtmxRenderContext ctx) => ctx.Writer.WriteUtf8(_errorData);
|
|
protected override void RenderAntiforgeryToken(HtmxRenderContext ctx) => ctx.Writer.WriteUtf8(_afTokenData);
|
|
}
|
|
|
|
|
|
[Handler]
|
|
[MapGet("/login")]
|
|
public static partial class GetLoginHandler
|
|
{
|
|
public class Query;
|
|
|
|
private static ValueTask<IResult> HandleAsync(
|
|
Query _,
|
|
IHttpContextAccessor httpContextAccessor,
|
|
IAntiforgery antiforgery,
|
|
CancellationToken token)
|
|
{
|
|
var ctx = httpContextAccessor.HttpContext
|
|
?? throw new InvalidOperationException("HttpContext is not available.");
|
|
|
|
if (ctx.User.Identity?.IsAuthenticated == true)
|
|
return ValueTask.FromResult<IResult>(new HtmxResult("/"));
|
|
|
|
var afTokens = antiforgery.GetAndStoreTokens(ctx);
|
|
return ValueTask.FromResult<IResult>(ctx.WriteHtmxPage(new Login(afToken: afTokens.RequestToken), title: "Sign in", appName: "HtmxApp", pageTitle: "Sign in"));
|
|
}
|
|
}
|
|
|
|
|
|
[Handler]
|
|
[MapPost("/login")]
|
|
public static partial class PostLoginHandler
|
|
{
|
|
public class Command
|
|
{
|
|
[FromForm] public string Email { get; set; } = default!;
|
|
[FromForm] public string Password { get; set; } = default!;
|
|
}
|
|
|
|
private static async ValueTask<IResult> HandleAsync(
|
|
[AsParameters] Command command,
|
|
IHttpContextAccessor httpContextAccessor,
|
|
IAntiforgery antiforgery,
|
|
AuthService authService,
|
|
CancellationToken token)
|
|
{
|
|
var ctx = httpContextAccessor.HttpContext
|
|
?? throw new InvalidOperationException("HttpContext is not available.");
|
|
|
|
var (success, error) = await authService.LoginAsync(command.Email, command.Password);
|
|
|
|
if (success)
|
|
return new HtmxResult("/");
|
|
|
|
var afTokens = antiforgery.GetAndStoreTokens(ctx);
|
|
return ctx.WriteHtmxPage(new Login(error, afToken: afTokens.RequestToken), title: "Sign in", appName: "HtmxApp", pageTitle: "Sign in");
|
|
}
|
|
}
|