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

Blazor登录问题:InteractiveServer下HttpContext为空的解决办法

解决Blazor InteractiveServer模式下Cookie登录的HttpContext为空问题

问题根源

Blazor InteractiveServer模式通过SignalR的WebSocket连接维持客户端与服务器的交互,仅在初始页面加载的HTTP请求生命周期内存在有效HttpContext,后续组件的交互(比如登录按钮点击)是通过SignalR消息传递,此时HttpContextAccessor.HttpContext会为空,导致无法直接调用SignInAsync完成Cookie认证。

推荐解决方案:通过API端点处理登录

将登录逻辑移至ASP.NET Core API控制器中,通过HTTP请求完成认证(此时HttpContext有效),Blazor组件仅负责收集用户输入并调用API。这种方式符合HTTP认证规范,也能完美适配InteractiveServer模式。

步骤1:创建登录API控制器

using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Authentication.Cookies;
using Microsoft.AspNetCore.Mvc;
using System.Security.Claims;
using DBDATA.Models;
using MUDTEMPLATE.Services;

[Route("api/[controller]")]
[ApiController]
public class AccountController : ControllerBase
{
    private readonly INguoidungService _nguoiDungService;

    public AccountController(INguoidungService nguoiDungService)
    {
        _nguoiDungService = nguoiDungService;
    }

    [HttpPost("Login")]
    public async Task<IActionResult> Login([FromBody] LoginVM model)
    {
        var user = await _nguoiDungService.FindByInfo(model.Name, model.Pass);
        if (user == null)
        {
            return BadRequest(new { ErrorMessage = "Wrong information" });
        }

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

        var identity = new ClaimsIdentity(claims, CookieAuthenticationDefaults.AuthenticationScheme);
        var principal = new ClaimsPrincipal(identity);

        await HttpContext.SignInAsync(CookieAuthenticationDefaults.AuthenticationScheme, principal);
        return Ok();
    }
}

public class LoginVM
{
    public string? Name { get; set; }
    public string? Pass { get; set; }
}

步骤2:修改Login.razor组件

移除IHttpContextAccessor注入,改用HttpClient调用API:

@page "/Account/Login"
@using System.ComponentModel.DataAnnotations
@inject HttpClient Http
@inject NavigationManager NavigationManager

@rendermode InteractiveServer

<div class="row">
    <div class="col-lg-4 offset-lg-4 pt-4 pb border">
        <EditForm Model="@Model" OnValidSubmit="Auth" FormName="LoginForm">
            <DataAnnotationsValidator />
            <div class="mb-3 text-center flex-column">
                <h3>Login</h3>
            </div>
            <div class="mb-3">
                <label>User Name</label>
                <InputText @bind-Value="Model.Name" class="form-control" placeholder="Username"></InputText>
                <ValidationMessage For="() => Model.Name" />
            </div>
            <div class="mb-3">
                <label>Password</label>
                <InputText @bind-Value="Model.Pass" class="form-control" placeholder="Password"></InputText>
                <ValidationMessage For="() => Model.Pass"/>
            </div>
            <div class="mb-3 text-center">
                @if(!string.IsNullOrEmpty(errorMessage)){
                    <span class="text-danger">@errorMessage</span>
                }  
            </div>
            <div class="mb-3 d-grid gap-2">
                <button type="submit" class="btn btn-primary">Login</button>
            </div>
        </EditForm>
    </div>
</div>

@code{
    public class LoginVM
    {
        [Required(ErrorMessage = "Name cannot be null")]
        public string? Name { get; set; }
        [Required(ErrorMessage = "Password cannot be null")]
        public string? Pass { get; set; }
    }

    public LoginVM Model = new();
    private string? errorMessage;

    private async Task Auth()
    {
        try
        {
            var response = await Http.PostAsJsonAsync("/api/Account/Login", Model);
            if (response.IsSuccessStatusCode)
            {
                NavigationManager.NavigateTo("/", true); // 强制刷新页面,确保认证状态生效
            }
            else
            {
                var error = await response.Content.ReadFromJsonAsync<dynamic>();
                errorMessage = error?.ErrorMessage ?? "Login failed";
            }
        }
        catch (Exception ex)
        {
            errorMessage = "An error occurred during login";
        }
    }
}

补充说明

  1. 确保已在Program.cs中配置Cookie认证:
builder.Services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme)
    .AddCookie(options =>
    {
        options.LoginPath = "/Account/Login";
        options.ExpireTimeSpan = TimeSpan.FromHours(8);
    });

// 注册HttpClient供Blazor组件使用
builder.Services.AddScoped(sp => new HttpClient { BaseAddress = new Uri(sp.GetRequiredService<NavigationManager>().BaseUri) });
  1. 原代码中的错误修正:
    • 拼写错误:HttpContent应为HttpContext,userService应为注入的nguoiDungService
    • 显示错误:错误提示应使用@errorMessage而非字符串"errorMessage"

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.21 14:32:13