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

ASP.NET Core 8 Blazor Server应用Cookie无法设置问题求助

ASP.NET Core 8 Blazor Server 认证后浏览器无Cookie问题修复

核心问题分析

你的代码存在几个关键问题,导致用户认证成功后浏览器无法收到Cookie:

  1. AuthService自行创建HttpClient,脱离浏览器上下文
    AuthService中手动实例化了HttpClientHandler和HttpClient,这个客户端的Cookie容器是服务端内存中的独立对象,和浏览器的Cookie存储完全无关。浏览器的Cookie依赖HTTP响应的Set-Cookie头传递,但服务端内部HttpClient发起的请求,响应Cookie只会存留在内部容器,不会同步到浏览器。

  2. CORS配置错误
    CORS策略中的WithOrigins("localhost")缺少协议(http/https)和端口信息,浏览器会因跨域规则限制拒绝接收Cookie。

  3. Cookie名称与认证方案不匹配
    CookieService设置的Cookie名为authToken,但Program.cs中Cookie认证方案的Cookie名是auth_token,两者不一致导致无法识别。同时SameSite和Secure配置在开发环境的适配逻辑有误。

  4. Blazor Server中API调用方式错误
    Blazor Server组件运行在服务端,直接用HttpClient调用本地API属于服务端内部请求,不会触发浏览器的Cookie存储流程,浏览器无法感知到响应中的Set-Cookie头。


分步修复方案

1. 重构AuthService,使用注入的HttpClient并对接HttpContext

删除手动创建的HttpClientHandler和HttpClient,直接使用DI注入的实例,通过IHttpContextAccessor访问浏览器传递的Cookie:

public class AuthService
{
    private readonly HttpClient _httpClient;
    private readonly ILogger<AuthService> _logger;
    private readonly IHttpContextAccessor _httpContextAccessor;

    public AuthService(HttpClient httpClient, ILogger<AuthService> logger, IHttpContextAccessor httpContextAccessor)
    {
        _httpClient = httpClient;
        _logger = logger;
        _httpContextAccessor = httpContextAccessor;

        if (_httpClient.BaseAddress == null)
        {
            _httpClient.BaseAddress = new Uri("https://localhost:7025/");
        }
    }

    public async Task<HttpResponseMessage> Login(LoginViewModel model)
    {
        try
        {
            _logger.LogInformation("正在发送登录请求。");
            var response = await _httpClient.PostAsJsonAsync("api/auth/login", model);

            if (response.IsSuccessStatusCode)
            {
                _logger.LogInformation("登录成功。");
            }
            else
            {
                _logger.LogWarning("登录失败,状态码: {StatusCode}", response.StatusCode);
            }

            return response;
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "登录请求过程中发生错误。");
            throw;
        }
    }

    public string GetAuthToken()
    {
        try
        {
            var token = _httpContextAccessor.HttpContext.Request.Cookies["authToken"];

            if (token != null)
            {
                _logger.LogInformation("获取到authToken Cookie: {Token}", token);
            }
            else
            {
                _logger.LogWarning("未找到authToken Cookie。");
            }

            return token;
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "获取authToken Cookie时发生错误。");
            throw;
        }
    }

    public HttpClient GetHttpClient()
    {
        return _httpClient;
    }
}

2. 修正CORS配置

更新Program.cs中的CORS策略,指定包含协议和端口的完整Origin地址:

builder.Services.AddCors(options =>
{
    options.AddPolicy("AllowSpecificOrigin",
        builder =>
        {
            // 替换为你的Blazor Server实际访问地址
            builder.WithOrigins("https://localhost:7025")
                   .AllowAnyMethod()
                   .AllowAnyHeader()
                   .AllowCredentials();
        });
});

3. 统一Cookie名称与环境适配配置

确保CookieService和Program.cs中的Cookie认证方案使用相同名称,并根据环境调整Secure策略:

CookieService.cs修改

public void SetAuthTokenCookie(string token)
{
    var isProduction = Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT") == Environments.Production;
    
    var cookieOptions = new CookieOptions
    {
        Expires = DateTime.Now.AddDays(30),
        HttpOnly = true,
        Secure = isProduction, // 开发环境用http时设为false,生产环境强制https
        SameSite = SameSiteMode.Lax,
        IsEssential = true
    };

    _httpContextAccessor.HttpContext.Response.Cookies.Append("authToken", token, cookieOptions);
    _logger.LogInformation("authToken Cookie已成功添加。");
}

Program.cs中Cookie认证配置修改

.AddCookie(CookieAuthenticationDefaults.AuthenticationScheme, options =>
{
    options.Cookie.Name = "authToken"; // 和CookieService保持一致
    options.LoginPath = "/login";
    options.AccessDeniedPath = "/access-denied";
    options.Cookie.HttpOnly = true;
    options.Cookie.SecurePolicy = Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT") == Environments.Production 
        ? CookieSecurePolicy.Always 
        : CookieSecurePolicy.None;
    options.Cookie.SameSite = SameSiteMode.Lax;
    options.ExpireTimeSpan = TimeSpan.FromDays(30);
    options.SlidingExpiration = true;
});

4. 调整登录逻辑,让浏览器直接处理Cookie

Blazor Server组件运行在服务端,需通过JS互操作让浏览器直接发起登录请求,确保Set-Cookie头被浏览器处理:

@page "/login"
@using System.Text.Json
@inject IJSRuntime JSRuntime
@inject NavigationManager NavigationManager

<EditForm Model="@loginModel" OnValidSubmit="HandleLogin">
    <DataAnnotationsValidator />
    <ValidationSummary />
    <InputText @bind-Value="loginModel.UserName" />
    <InputText @bind-Value="loginModel.Password" type="password" />
    <div class="text-danger">@errorMessage</div>
    <button type="submit">登录</button>
</EditForm>

@code {
    private LoginViewModel loginModel = new LoginViewModel();
    private string errorMessage = string.Empty;

    private async Task HandleLogin()
    {
        try
        {
            var response = await JSRuntime.InvokeAsync<HttpResponseMessage>("fetch", "api/auth/login", new
            {
                method = "POST",
                headers = new { ["Content-Type"] = "application/json" },
                credentials = "include", // 确保浏览器发送/接收Cookie
                body = JsonSerializer.Serialize(loginModel)
            });

            if (response.IsSuccessStatusCode)
            {
                NavigationManager.NavigateTo("/");
            }
            else
            {
                errorMessage = await response.Content.ReadAsStringAsync();
            }
        }
        catch (Exception ex)
        {
            errorMessage = ex.Message;
        }
    }
}

5. 修正中间件顺序

确保Program.cs中的中间件顺序符合规范,CORS必须放在认证之前:

app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseCors("AllowSpecificOrigin"); // CORS中间件必须在认证前
app.UseAuthentication();
app.UseAuthorization();
app.UseSession();
app.MapControllers();
app.MapBlazorHub();
app.MapFallbackToPage("/_Host");

验证步骤

  1. 启动应用,打开浏览器开发者工具(F12),切换到Network标签。
  2. 提交登录请求,查看响应头中是否包含Set-Cookie: authToken=...。
  3. 切换到Application标签,查看当前域名的Cookies列表是否存在authToken。
  4. 导航到首页,查看请求头中是否携带Cookie: authToken=...。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.18 17:44:56