.Net Blazor 控制器 HttpContext.SignOutAsync() 不会使 cookie 失效

问题描述 投票:0回答:1

我正在尝试注销用户,但 cookie 并未失效。相反,我只是重定向到指定的路径,并且仍然可以访问所有内容。

控制器中的 onLogin 函数与 SignInAsync 工作得很好。

当我在调试中进入它时,ControllerBase.HttpContext.User.Identity.IsAuthenticated 始终为 false。

程序.cs

using Microsoft.AspNetCore.Authentication.Cookies;
using Microsoft.AspNetCore.Authorization;
using MudBlazor.Services;
using PersonalWebsiteRedesign.Classes.Database;
using PersonalWebsiteRedesign.Components;
using System.Net;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddRazorComponents()
    .AddInteractiveServerComponents()
    .AddInteractiveWebAssemblyComponents();

builder.Services.AddDbContext<SQL_DB_Context>();
builder.Services.AddControllers();
builder.Services.AddMudServices();

builder.Services.AddHttpContextAccessor();

builder.Services.AddScoped(sp => new HttpClient(new HttpClientHandler
{
    UseCookies = true,
    Credentials = CredentialCache.DefaultCredentials
})
{
    BaseAddress = new Uri("https://localhost:7043/")
});

builder.Services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme).AddCookie(CookieAuthenticationDefaults.AuthenticationScheme, options =>
{
    options.Cookie.Name = "fslr_auth"; 
    options.AccessDeniedPath = "/error";
    options.LogoutPath = "/user/logout";
    options.LoginPath = "/user/login";
    options.ExpireTimeSpan = TimeSpan.FromMinutes(60);
    options.Cookie.SameSite = SameSiteMode.Strict;
    options.Cookie.HttpOnly = true;
    options.Cookie.SecurePolicy = CookieSecurePolicy.Always;
    options.Cookie.IsEssential = true;
    options.Cookie.Path = "/";
    options.SlidingExpiration = true;
});
builder.Services.AddAuthorization(options =>
{
    options.AddPolicy("Cookies", policy => policy.RequireAuthenticatedUser());
});
builder.Services.AddSingleton<IAuthorizationPolicyProvider, DefaultAuthorizationPolicyProvider>();

builder.Services.AddCascadingAuthenticationState();

var app = builder.Build();

// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
    app.UseWebAssemblyDebugging();
}
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.UseHttpsRedirection();

app.UseStaticFiles();
app.UseAntiforgery();

app.UseAuthentication();
app.UseAuthorization();

app.MapRazorComponents<App>()
    .AddInteractiveServerRenderMode()
    .AddInteractiveWebAssemblyRenderMode()
    .AddAdditionalAssemblies(typeof(PersonalWebsiteRedesign.Client._Imports).Assembly);

app.MapControllers();

app.Run();

AuthController.cs

[ApiController]
public class AuthController : ControllerBase
{
SQL_DB_Context dbContext;
public AuthController(SQL_DB_Context _dbContext)
{
    dbContext = _dbContext;
}

[HttpPost]
[Route("api/auth/login")]
public async Task<IActionResult> onLogin([FromBody] LoginUserForm loginUserForm)
{
    if (loginUserForm != null && dbContext.Users.Any(x => x.username == loginUserForm.UserName))
    {
        var userid = dbContext.Users.Where(x => x.username == loginUserForm.UserName).FirstOrDefault().id;
        var roleid = dbContext.UserRoles.Where(x => x.id == userid).FirstOrDefault().roleId;
        var roleToString = dbContext.RolesList.Where(x => x.id == roleid).FirstOrDefault().Role;

        var claims = new List<Claim>
        {
            new Claim(ClaimTypes.Name, loginUserForm.UserName),
            new Claim(ClaimTypes.Role, roleToString)
        };

        var claimsIdentity = new ClaimsIdentity(claims, CookieAuthenticationDefaults.AuthenticationScheme);

        await HttpContext.SignInAsync(CookieAuthenticationDefaults.AuthenticationScheme, new ClaimsPrincipal(claimsIdentity));
        return this.Ok();
    } else
    {
        return this.BadRequest();
    }
}

[HttpPost]
[Route("api/auth/logout")]
public async Task<IActionResult> onLogout()
{
    await HttpContext.SignOutAsync(CookieAuthenticationDefaults.AuthenticationScheme);
    return this.Ok();
}

注销.razor

page "/user/logout"
@using Microsoft.AspNetCore.Authorization
@using Microsoft.AspNetCore.Http
@using System.Net
@rendermode InteractiveServer
@attribute [Authorize]

@inject NavigationManager navManager
@inject HttpClient HttpClient
@inject IHttpContextAccessor httpContextAccessor
@code {
    protected override async Task OnAfterRenderAsync(bool firstRender)
    {
        if(firstRender)
        {
            await onLogout();
        }
    }
    private async Task onLogout()
    {
        var baseAddress = new Uri(navManager.BaseUri);
        var cookieContainer = new CookieContainer();
        using (var handler = new HttpClientHandler() { CookieContainer = cookieContainer })
        using (var client = new HttpClient(handler) { BaseAddress = baseAddress })
        {
            var result = await client.PostAsync("api/auth/logout", null, CancellationToken.None);
            if (result.IsSuccessStatusCode)
            {
                navManager.NavigateTo("/user/login", true);
                Console.WriteLine("Logged out user: " + httpContextAccessor.HttpContext.User.Identity.Name + ", Status: " + httpContextAccessor.HttpContext.User.Identity.IsAuthenticated);
            }
            else
            {
                Console.WriteLine("Couldn't logout user.");
            }
            var x = "";
        }
    }
}
c# asp.net-core blazor
1个回答
0
投票

为了确保身份验证 cookie 在注销后失效,您需要从客户端显式清除身份验证 cookie。目前,服务器上的 SignOutAsync 方法会删除身份验证,但 cookie 仍保留在浏览器中,这可能会导致用户仍被识别为已通过身份验证。

这是你应该做的:

  1. 在 Logout.razor 中,向服务器发送注销请求后,通过添加以下行来清除客户端上的身份验证 cookie:
cookieContainer.Add(baseAddress, new Cookie(".AspNetCore.Cookies", ""));

这会强制浏览器删除负责用户身份验证的 .AspNetCore.Cookies cookie。

  1. 更新的 onLogout() 方法:
private async Task onLogout()
{
    var baseAddress = new Uri(navManager.BaseUri);
    var cookieContainer = new CookieContainer();
    using (var handler = new HttpClientHandler() { CookieContainer = cookieContainer })
    using (var client = new HttpClient(handler) { BaseAddress = baseAddress })
    {
        var result = await client.PostAsync("api/auth/logout", null, CancellationToken.None);
        if (result.IsSuccessStatusCode)
        {
            // Clear the authentication cookie
            cookieContainer.Add(baseAddress, new Cookie(".AspNetCore.Cookies", ""));

            navManager.NavigateTo("/user/login", true);
            Console.WriteLine("Logged out user: " + httpContextAccessor.HttpContext.User.Identity.Name + ", Status: " + httpContextAccessor.HttpContext.User.Identity.IsAuthenticated);
        }
        else
        {
            Console.WriteLine("Couldn't logout user.");
        }
    }
}

这可确保 cookie 从服务器和客户端中删除,从而完全注销用户。

© www.soinside.com 2019 - 2024. All rights reserved.