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

如何在MudBlazor的所有Razor组件中访问HttpContext?

在MudBlazor中无法从Blazor组件访问HttpContext.Session的解决方案

问题本质

Blazor组件(不管是Blazor Server还是WASM)的执行模型和传统Razor Pages/MVC完全不同:

  • Blazor Server中,HttpContext仅与初始请求绑定,后续组件渲染依赖SignalR连接,此时直接访问HttpContext.Session大概率拿不到值(因为不在请求上下文范围内)。
  • Blazor WASM中根本不存在服务器端的HttpContext,自然无法访问Session。

所以直接通过HttpContext.Session传递身份状态的方式,不适用于Blazor组件场景。

推荐解决方案:使用Blazor内置的AuthenticationStateProvider

Blazor提供了AuthenticationStateProvider来统一管理身份验证状态,这是适配Blazor执行模型的标准方案,具体步骤如下:

1. 自定义AuthenticationStateProvider

创建一个自定义类,集成AuthenticationStateProvider,用来读取你已获取的JWT令牌和角色信息:

public class CustomAuthStateProvider : AuthenticationStateProvider
{
    // Blazor Server场景注入IHttpContextAccessor,WASM场景替换为IJSRuntime
    private readonly IHttpContextAccessor _httpContextAccessor;

    public CustomAuthStateProvider(IHttpContextAccessor httpContextAccessor)
    {
        _httpContextAccessor = httpContextAccessor;
    }

    public override async Task<AuthenticationState> GetAuthenticationStateAsync()
    {
        // 从Session读取身份标识和JWT令牌
        var authFlag = _httpContextAccessor.HttpContext?.Session.GetString("authentication");
        var jwtToken = _httpContextAccessor.HttpContext?.Session.GetString("jwtToken");

        if (string.IsNullOrEmpty(authFlag) || string.IsNullOrEmpty(jwtToken))
        {
            // 返回未认证状态
            return new AuthenticationState(new ClaimsPrincipal(new ClaimsIdentity()));
        }

        // 解析JWT中的Claims(包含角色信息)
        var claims = ParseJwtClaims(jwtToken);
        // 创建身份标识
        var identity = new ClaimsIdentity(claims, "CustomAuth");
        var user = new ClaimsPrincipal(identity);

        return new AuthenticationState(user);
    }

    // 解析JWT的辅助方法
    private IEnumerable<Claim> ParseJwtClaims(string jwt)
    {
        var payload = jwt.Split('.')[1];
        // 补全Base64 padding
        var decodedBytes = Convert.FromBase64String(payload.PadRight(payload.Length + (4 - payload.Length % 4) % 4, '='));
        var claimsDict = JsonSerializer.Deserialize<Dictionary<string, object>>(decodedBytes);
        
        return claimsDict.Select(kvp => new Claim(kvp.Key, kvp.Value.ToString()));
    }

    // 登录/登出后更新身份状态的方法
    public void UpdateAuthState(bool isAuthenticated, string jwtToken = null)
    {
        ClaimsPrincipal user;
        if (isAuthenticated && !string.IsNullOrEmpty(jwtToken))
        {
            var claims = ParseJwtClaims(jwtToken);
            var identity = new ClaimsIdentity(claims, "CustomAuth");
            user = new ClaimsPrincipal(identity);
        }
        else
        {
            user = new ClaimsPrincipal(new ClaimsIdentity());
        }

        NotifyAuthenticationStateChanged(Task.FromResult(new AuthenticationState(user)));
    }
}

2. 注册服务

在Program.cs中注册自定义身份验证提供者和必要依赖:

// 注册IHttpContextAccessor(仅Blazor Server需要)
builder.Services.AddHttpContextAccessor();
// 注册自定义AuthStateProvider
builder.Services.AddScoped<AuthenticationStateProvider, CustomAuthStateProvider>();
// 启用会话(如果还未配置)
builder.Services.AddSession(options =>
{
    options.IdleTimeout = TimeSpan.FromHours(1);
    options.Cookie.HttpOnly = true;
});

3. 在cshtml身份验证页面中更新状态

登录成功后,除了设置Session,还要调用自定义提供者的更新方法:

public async Task<IActionResult> Login(LoginModel model)
{
    // 你的JWT获取逻辑
    var jwtToken = "获取到的JWT令牌";
    
    // 设置Session
    HttpContext.Session.SetString("authentication", "true");
    HttpContext.Session.SetString("jwtToken", jwtToken);

    // 更新Blazor身份状态
    var authStateProvider = HttpContext.RequestServices.GetRequiredService<CustomAuthStateProvider>();
    authStateProvider.UpdateAuthState(true, jwtToken);

    return RedirectToPage("/Index");
}

4. 在Blazor组件中使用身份状态

以NavMenu.razor为例:

@inject AuthenticationStateProvider AuthStateProvider
@using System.Security.Claims

<div class="nav-menu">
    @if (isAuthenticated)
    {
        <MudNavLink Href="/dashboard">仪表盘</MudNavLink>
        <MudNavLink Href="/profile">个人中心</MudNavLink>
    }
    else
    {
        <MudNavLink Href="/login">登录</MudNavLink>
    }
</div>

@code {
    private bool isAuthenticated;
    private ClaimsPrincipal currentUser;

    protected override async Task OnInitializedAsync()
    {
        // 订阅身份状态变化
        AuthStateProvider.AuthenticationStateChanged += AuthStateChanged;
        // 初始加载身份状态
        await LoadAuthState();
    }

    private async Task LoadAuthState()
    {
        var authState = await AuthStateProvider.GetAuthenticationStateAsync();
        currentUser = authState.User;
        isAuthenticated = currentUser.Identity.IsAuthenticated;
        StateHasChanged();
    }

    private void AuthStateChanged(Task<AuthenticationState> task)
    {
        _ = LoadAuthState();
    }

    public void Dispose()
    {
        AuthStateProvider.AuthenticationStateChanged -= AuthStateChanged;
    }
}

备选方案:通过组件参数传递Session值(仅Blazor Server预渲染场景)

如果不想使用AuthenticationStateProvider,可以在_Host.cshtml中将Session值作为参数传递给Blazor根组件:

@page "/"
@using Microsoft.AspNetCore.Http
@inject IHttpContextAccessor HttpContextAccessor

<component type="typeof(App)" render-mode="ServerPrerendered" 
           param-IsAuthenticated="@(HttpContextAccessor.HttpContext?.Session.GetString("authentication") == "true")" />

然后在App.razor中接收参数,通过级联值传递给子组件:

<CascadingValue Name="IsAuthenticated" Value="IsAuthenticated">
    <Router AppAssembly="@typeof(App).Assembly">
        <!-- 路由内容 -->
    </Router>
</CascadingValue>

@code {
    [Parameter]
    public bool IsAuthenticated { get; set; }
}

最后在NavMenu.razor中接收级联值:

[CascadingParameter(Name = "IsAuthenticated")]
private bool IsAuthenticated { get; set; }

<!-- 组件内容 -->

注意:这种方案仅在初始预渲染时传递值,后续Session变化不会自动同步到组件,需要手动处理刷新逻辑。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.02 18:15:26