Hi all,
I'm learning Blazor (.NET 9 on VS2022). I'm trying to develop a simple login page, but I keep getting the error: "A valid antiforgery token was not provided with the request. Add an antiforgery token, or disable antiforgery validation for this endpoint.".
Can anybody please help me?
program.cs
Code:
using M2M;
using M2M.Components;
using M2M.Components.Account;
using M2M.Data;
using M2M.Models.User;
using Microsoft.AspNetCore.Authentication.Cookies;
using Microsoft.AspNetCore.Components.Authorization;
using Microsoft.AspNetCore.Identity;
using Microsoft.EntityFrameworkCore;
using Syncfusion.Blazor;
var builder = WebApplication.CreateBuilder(args);
string pgSQLServer = builder.Configuration.GetSection("PG_SQL").GetSection("Server").Value;
string pgSQLDBName = builder.Configuration.GetSection("PG_SQL").GetSection("DB_Name").Value;
string pgSQLDBUser = builder.Configuration.GetSection("PG_SQL").GetSection("DB_User").Value;
string pgSQLDBPassword = builder.Configuration.GetSection("PG_SQL").GetSection("DB_User_Password").Value;
int pgPoolSize = Convert.ToInt32(builder.Configuration.GetSection("PG_SQL").GetSection("DB_Pool_Size").Value);
string pgSQLConnectionString = "Server=" + M2M.Models.AppSettings.PG_SQL.Server + ";Database=" + M2M.Models.AppSettings.PG_SQL.DB_Name + ";Port=5432;User ID=" + M2M.Models.AppSettings.PG_SQL.DB_User + ";Password=" + M2M.Models.AppSettings.PG_SQL.DB_User_Password + ";Keepalive=300; Pooling = true; Minimum Pool Size = 0; Maximum Pool Size = " + pgPoolSize + "; Connection Idle Lifetime=300; CommandTimeout=300; Tcp Keepalive=true; Include Error Detail=true";
M2M.Models.AppSettings.PG_SQL.Connection_String = pgSQLConnectionString;
// Add services to the container.
builder.Services.AddRazorComponents().AddInteractiveServerComponents();
builder.Services.AddSignalR(o => { o.MaximumReceiveMessageSize = 102400000; });
builder.Services.AddSyncfusionBlazor();
//builder.Services.AddSingleton<PdfService>();
//builder.Services.AddSingleton<ExcelService>();
builder.Services.AddMemoryCache();
builder.Services.AddCascadingAuthenticationState();
builder.Services.AddScoped<IUserManager, UserManager>();
builder.Services.AddScoped<IUserRepository, UserRepository>();
builder.Services.AddDbContext<CookieReadersContext>(options =>
{
options.UseNpgsql(pgSQLConnectionString);
});
builder.Services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme).AddCookie(options =>
{
options.Cookie.Name = ".AspNetCore.Cookies";
options.LoginPath = "/";
options.ReturnUrlParameter = "ReturnUrl";
options.AccessDeniedPath = "/Access_Denied";
options.LogoutPath = "/Logout";
options.SlidingExpiration = true;
options.ExpireTimeSpan = TimeSpan.FromHours(M2M.Models.AppSettings.SESSION_TIMEOUT);
options.Cookie.MaxAge = options.ExpireTimeSpan;
});
builder.Services.AddTransient<CustomCookieAuthenticationEvents>();
builder.Services.AddHttpContextAccessor();
builder.Services.AddMemoryCache();
builder.Services.AddAntiforgery(opts => opts.Cookie.Name = "__RequestVerificationToken");
builder.Services.Configure<CookiePolicyOptions>(options =>
{
// This lambda determines whether user consent for non-essential cookies is needed for a given request.
options.Secure = CookieSecurePolicy.Always;
options.CheckConsentNeeded = context => true;
options.MinimumSameSitePolicy = SameSiteMode.None;
});
builder.Services.AddScoped<AppStateService>();
var app = builder.Build();
// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
app.UseMigrationsEndPoint();
}
else
{
app.UseExceptionHandler("/Error", createScopeForErrors: true);
// The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
app.UseHsts();
}
app.UseCookiePolicy();
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseAuthentication();
app.UseAuthorization();
app.UseAntiforgery();
app.MapStaticAssets();
app.MapRazorComponents<App>()
.AddInteractiveServerRenderMode();
// Add additional endpoints required by the Identity /Account Razor components.
app.MapAdditionalIdentityEndpoints();
app.Run();
login.razor
Code:
@page "/"
@using System.ComponentModel.DataAnnotations
@using M2M.Models.User
@using Microsoft.AspNetCore.Authentication
@using Microsoft.AspNetCore.Authorization
@using Microsoft.AspNetCore.Identity
@using M2M.Data
@inject AppStateService appStateService
@inject NavigationManager NavManager
@inject IJSRuntime JSRuntime
@inject IUserRepository UserRepositoty
@inject ILogger<Login> Logger
@inject NavigationManager NavigationManager
@attribute [AllowAnonymous]
<PageTitle>Log in</PageTitle>
<h1>Log in</h1>
<div class="row">
<div class="col-lg-6">
<section>
<StatusMessage Message="@errorMessage" />
<EditForm Model="Input" method="post" OnValidSubmit="LoginUser" FormName="login">
<DataAnnotationsValidator />
<AntiforgeryToken />
<h2>Use a local account to log in.</h2>
<hr />
<div class="form-floating mb-3">
<InputText @bind-Value="Input.Email" id="Input.Email" class="form-control" autocomplete="username" aria-required="true" placeholder="name@example.com" />
<label for="Input.Email" class="form-label">Email</label>
<ValidationMessage For="() => Input.Email" class="text-danger" />
</div>
<div class="form-floating mb-3">
<InputText type="password" @bind-Value="Input.Password" id="Input.Password" class="form-control" autocomplete="current-password" aria-required="true" placeholder="password" />
<label for="Input.Password" class="form-label">Password</label>
<ValidationMessage For="() => Input.Password" class="text-danger" />
</div>
<div class="checkbox mb-3">
<label class="form-label">
<InputCheckbox @bind-Value="Input.RememberMe" class="darker-border-checkbox form-check-input" />
Remember me
</label>
</div>
<div>
<button type="submit" class="w-100 btn btn-lg btn-primary">Log in</button>
</div>
<div>
<p>
<a href="Account/ForgotPassword">Forgot your password?</a>
</p>
<p>
<a href="@(NavigationManager.GetUriWithQueryParameters("Account/Register", new Dictionary<string, object?> { ["ReturnUrl"] = ReturnUrl }))">Register as a new user</a>
</p>
<p>
<a href="Account/ResendEmailConfirmation">Resend email confirmation</a>
</p>
</div>
</EditForm>
</section>
</div>
@* <div class="col-lg-4 col-lg-offset-2">
<section>
<h3>Use another service to log in.</h3>
<hr />
<ExternalLoginPicker />
</section>
</div> *@
</div>
@code {
private string? errorMessage;
[CascadingParameter]
private HttpContext HttpContext { get; set; } = default!;
private UserManager UserManager { get; set; } = new UserManager();
[SupplyParameterFromForm]
private Models.User.Login 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 UserManager.SignOut(this.HttpContext);
}
}
public async Task LoginUser()
{
var result = await UserManager.SignIn(this.HttpContext, Input);
if (result.usersPid > 0)
{
Logger.LogInformation("User logged in.");
RedirectManager.RedirectTo(ReturnUrl);
}
else
{
// blah blah blah
}
}
}