You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Blazor Server与.NET 6 API认证Cookie串户问题求助

问题排查与解决方案

核心问题分析

从你的代码和描述来看,最可能导致串户的原因是HttpClientHandler的生命周期配置错误,其次是中间件顺序、sessionid获取方式等问题,以下是具体排查和修复步骤:


1. 修复HttpClientHandler共享问题(最优先)

你在Blazor Server的Program.cs中设置了SetHandlerLifetime(Timeout.InfiniteTimeSpan),这会让HttpClientHandler成为单例对象。而Blazor Server中HttpClient是Scoped的,多个用户的请求会共享同一个Handler的CookieContainer,直接导致不同用户的认证Cookie被混用,出现串户。

修复代码:
移除无限生命周期设置,恢复默认Handler生命周期:

builder.Services.AddHttpClient(Microsoft.Extensions.Options.Options.DefaultName, options =>
{
    options.BaseAddress = new Uri(ProprietaryAPI.baseURI);
});

如果需要自定义Handler,确保每个用户拥有独立的Handler实例:

builder.Services.AddScoped<HttpClientHandler>();
builder.Services.AddHttpClient(Microsoft.Extensions.Options.Options.DefaultName, (sp, client) =>
{
    client.BaseAddress = new Uri(ProprietaryAPI.baseURI);
}).ConfigurePrimaryHttpMessageHandler(sp => sp.GetRequiredService<HttpClientHandler>());

2. 修正sessionid获取方式

你当前通过HttpContext.Request.Headers.TryGetValue("sessionid", out var val)获取sessionid,这种方式依赖前端手动传递Header,容易出错且不安全。正确的做法是从认证后的ClaimsPrincipal中读取,因为登录时你已经将sessionid添加到Claims中:

修复代码(API端):

// 替换原来的Header获取方式
var sessionId = HttpContext.User.FindFirstValue("sessionid");
if (!string.IsNullOrEmpty(sessionId))
{
    // 使用sessionid获取用户信息
}
else
{
    // 未认证处理逻辑
}

3. 调整Blazor Server中间件顺序

你的Blazor Server中间件顺序错误,UseRouting应该放在UseHttpsRedirection、UseStaticFiles之后,UseAuthentication、UseAuthorization之前,否则认证信息无法正确传递到Blazor Hub。

修复后的中间件顺序:

var app = builder.Build();

if (!app.Environment.IsDevelopment())
{
    app.UseExceptionHandler("/Error");
    app.UseHsts();
}

app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseCookiePolicy();

app.UseRouting();

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

app.UseEndpoints(endpoints =>
{
    endpoints.MapRazorPages();
    endpoints.MapBlazorHub();
    endpoints.MapFallbackToPage("/_Host");
});

app.Run();

4. 优化API的Cookie配置

为避免Cookie冲突,给认证Cookie设置唯一名称,并强化安全属性:

builder.Services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme)
    .AddCookie(options => 
    {
        options.LoginPath = "/api/Proprietary/NewLogin"; 
        options.Cookie.SameSite = SameSiteMode.None; 
        options.Cookie.SecurePolicy = CookieSecurePolicy.Always;
        options.Cookie.Name = "MyAppAuthCookie"; // 设置唯一Cookie名称
        options.Cookie.HttpOnly = true; // 防止XSS攻击
        options.Cookie.IsEssential = true; // 无需用户同意
    });

5. 检查CustomAuthStateProvider实现

确保你的CustomAuthStateProvider是Scoped生命周期,且能正确响应用户登录状态变化:

public class CustomAuthStateProvider : AuthenticationStateProvider
{
    private readonly AuthService _authService;

    public CustomAuthStateProvider(AuthService authService)
    {
        _authService = authService;
        _authService.OnAuthStateChanged += () => NotifyAuthenticationStateChanged(GetAuthenticationStateAsync());
    }

    public override async Task<AuthenticationState> GetAuthenticationStateAsync()
    {
        var sessionId = await _authService.GetSessionIdAsync();
        if (string.IsNullOrEmpty(sessionId))
        {
            return new AuthenticationState(new ClaimsPrincipal(new ClaimsIdentity()));
        }

        var claims = new List<Claim> { new Claim("sessionid", sessionId) };
        var identity = new ClaimsIdentity(claims, "CustomAuth");
        return new AuthenticationState(new ClaimsPrincipal(identity));
    }
}

在AuthService登录成功后,触发OnAuthStateChanged事件,确保Provider及时更新当前用户的认证状态。


6. Azure环境配置检查

  • 开启会话亲和性:在Azure Portal的App Service -> 配置 -> 常规设置中,将「会话亲和性」设置为开启,确保Blazor Server的SignalR连接始终路由到同一实例,避免状态丢失。
  • 多实例一致性:如果App Service使用多实例部署,确保所有实例的配置一致,无共享缓存或状态的逻辑。

内容的提问来源于stack exchange,提问作者willjacobball

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.03 09:06:02