I have a situation that I belive the problem is the life cicle of the components, using blazor server-side and .net 8.
Using the structure that blazor ofers me, after going from the login page where the user can log in with email and password, I’m being redirect to the ‘LoginWith2fa’ page to insert the two-factor autenticator code. When i try to submit my form using OnValidSubmit the Input text of my code is empty.
This is static mode, if i try to use InterctiveServer it work, but I’ll have another problem when I call some of the extensions methods of SignInManager like in OnInitialized or anywhere else saing that ‘The response has already started’.
The login page after the login just call IdentityRedirectManager.RedirectTo(“/Account/LoginWith2fa”)
@page "/Account/LoginWith2fa"
@using System.ComponentModel.DataAnnotations
@using Microsoft.AspNetCore.Identity
@using BrokerWeb.Server.Data;
@using BrokerWeb.Server.Data.Identity
@inject SignInManager<ApplicationUser> SignInManager
@inject UserManager<ApplicationUser> UserManager
@inject IdentityRedirectManager RedirectManager
@inject ILogger<LoginWith2fa> Logger
<PageTitle>Two-factor authentication</PageTitle>
<EditForm FormName="MFAAuthentication" Model="Input" OnValidSubmit="this.OnValidSubmitAsync">
<MudPaper Class="pa-6" Elevation="15" MaxWidth="500px" Style="margin:auto; margin-top:50px;">
<MudCard>
<MudCardContent>
<MudText Typo="Typo.h4" Align="Align.Center">Two-factor authentication</MudText>
<MudDivider Class="mb-4" />
<MudAlert Severity="MudBlazor.Severity.Info" Dense="true">
Seu login é protegido com autenticação em dois fatores. Informe o código de autenticação!
</MudAlert>
<DataAnnotationsValidator />
<ValidationSummary class="text-danger" role="alert" />
<MudTextField Label="MFA"
@bind-Value="Input.TwoFactorCode"
For="@(() => Input.TwoFactorCode)"
Margin="Margin.Dense"
Variant="Variant.Outlined"
AdornmentColor="Color.Primary"
Adornment="Adornment.Start"
T="string"
MaxLength="6" />
<MudText Error="@ErrorMessage" Class="text-danger mb-2" />
<MudCheckBox @bind-Checked="@Input.RememberMachine"
Label="Lembre-se de mim"
T="bool" />
</MudCardContent>
<MudCardActions>
<MudButton ButtonType="ButtonType.Submit"
Variant="Variant.Filled"
Color="Color.Primary"
FullWidth="true">
Log In
</MudButton>
</MudCardActions>
</MudCard>
</MudPaper>
</EditForm>
@code {
private string ErrorMessage = string.Empty;
private ApplicationUser user = default!;
private InputModel Input { get; set; }
= new InputModel();
[SupplyParameterFromQuery]
private string ReturnUrl { get; set; }
[SupplyParameterFromQuery]
private bool RememberMe { get; set; }
protected override async Task OnInitializedAsync()
{
user = await SignInManager.GetTwoFactorAuthenticationUserAsync() ??
throw new InvalidOperationException("Unable to load two-factor authentication user.");
}
private async Task OnValidSubmitAsync()
{
var userId = await UserManager.GetUserIdAsync(user);
try
{
if (string.IsNullOrEmpty(Input.TwoFactorCode))
throw new ArgumentException("Código de autenticacao não informado!");
var authenticatorCode = Input.TwoFactorCode!.Replace(" ", string.Empty).Replace("-", string.Empty);
var result = await SignInManager.TwoFactorAuthenticatorSignInAsync(authenticatorCode, RememberMe, Input.RememberMachine);
if (result.Succeeded)
{
Logger.LogInformation("Usuário id '{UserId}' logou com 2fa!", userId);
RedirectManager.RedirectTo(ReturnUrl);
}
else if (result.IsLockedOut)
{
Logger.LogWarning("Conta do usuário id '{UserId}' bloqueada!", userId);
RedirectManager.RedirectTo("Account/Lockout");
}
else
throw new ArgumentException("Código de autenticação informado é inválido!");
}
catch (Exception exception)
{
Logger.LogWarning(exception.Message);
ErrorMessage = exception.Message;
}
}
private sealed class InputModel
{
[Required]
public string TwoFactorCode { get; set; }
public bool RememberMachine { get; set; }
}
}