Files
openarchival/OpenArchival.Blazor/Components/Account/Pages/Login.razor
2025-07-16 21:34:12 -04:00

122 lines
4.5 KiB
Plaintext

@page "/Account/Login"
@using System.ComponentModel.DataAnnotations
@using Microsoft.AspNetCore.Authentication
@using Microsoft.AspNetCore.Identity
@using OpenArchival.Blazor.Data
@inject SignInManager<ApplicationUser> SignInManager
@inject ILogger<Login> Logger
@inject NavigationManager NavigationManager
@inject IdentityRedirectManager RedirectManager
<PageTitle>Log in</PageTitle>
<MudText Typo="Typo.h3" GutterBottom="true">Log in</MudText>
<MudGrid>
<MudItem md="6">
<StatusMessage Message="@errorMessage" />
<EditForm Model="Input" method="post" OnValidSubmit="LoginUser" FormName="login">
<DataAnnotationsValidator />
<MudText GutterBottom="true" Typo="Typo.body1">Use a local account to log in.</MudText>
<MudGrid>
<MudItem md="12">
<MudStaticTextField For="@(() => Input.Email)" @bind-Value="Input.Email"
Label="Email" Placeholder="name@example.com"
UserAttributes="@(new() { { "autocomplete", "username" }, { "aria-required", "true" } } )" />
</MudItem>
<MudItem md="12">
<MudStaticTextField For="@(() => Input.Password)" @bind-Value="Input.Password"
Label="Password" InputType="InputType.Password" Placeholder="password"
UserAttributes="@(new() { { "autocomplete", "current-password" }, { "aria-required", "true" } } )" />
</MudItem>
<MudItem md="12">
<MudStaticCheckBox For="@(() => Input.RememberMe)" @bind-Value="Input.RememberMe">Remember me</MudStaticCheckBox>
</MudItem>
<MudItem md="12">
<MudStaticButton Variant="Variant.Filled" Color="Color.Primary" FullWidth="true" FormAction="FormAction.Submit">Log in</MudStaticButton>
</MudItem>
</MudGrid>
</EditForm>
<MudGrid Class="mt-4">
<MudItem md="12">
<MudLink Href="Account/ForgotPassword">Forgot your password?</MudLink><br />
<MudLink Href="@(NavigationManager.GetUriWithQueryParameters("Account/Register", new Dictionary<string, object?> { ["ReturnUrl"] = ReturnUrl }))">Register as a new user</MudLink><br />
<MudLink Href="Account/ResendEmailConfirmation">Resend email confirmation</MudLink>
</MudItem>
</MudGrid>
</MudItem>
<MudItem md="6">
<MudText GutterBottom="true" Typo="Typo.body1">Use another service to log in.</MudText>
<ExternalLoginPicker />
</MudItem>
</MudGrid>
@code {
private string? errorMessage;
[CascadingParameter]
private HttpContext HttpContext { get; set; } = default!;
[SupplyParameterFromForm]
private InputModel Input { get; set; } = new();
[SupplyParameterFromQuery]
private string? ReturnUrl { get; set; }
protected override async Task OnInitializedAsync()
{
if (HttpMethods.IsGet(HttpContext.Request.Method))
{
// Clear the existing external cookie to ensure a clean login process
await HttpContext.SignOutAsync(IdentityConstants.ExternalScheme);
}
}
public async Task LoginUser()
{
// This doesn't count login failures towards account lockout
// To enable password failures to trigger account lockout, set lockoutOnFailure: true
var result = await SignInManager.PasswordSignInAsync(Input.Email, Input.Password, Input.RememberMe, lockoutOnFailure: false);
if (result.Succeeded)
{
Logger.LogInformation("User logged in.");
RedirectManager.RedirectTo(ReturnUrl);
}
else if (result.RequiresTwoFactor)
{
RedirectManager.RedirectTo(
"Account/LoginWith2fa",
new() { ["returnUrl"] = ReturnUrl, ["rememberMe"] = Input.RememberMe });
}
else if (result.IsLockedOut)
{
Logger.LogWarning("User account locked out.");
RedirectManager.RedirectTo("Account/Lockout");
}
else
{
errorMessage = "Error: Invalid login attempt.";
}
}
private sealed class InputModel
{
[Required]
[EmailAddress]
public string Email { get; set; } = "";
[Required]
[DataType(DataType.Password)]
public string Password { get; set; } = "";
[Display(Name = "Remember me?")]
public bool RememberMe { get; set; }
}
}