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

Blazor自定义授权状态刷新后失效问题求助

Blazor自定义AuthenticationStateProvider刷新后认证状态丢失问题解决方案

问题根源分析

  1. 拼写错误:自定义认证状态提供者类名、方法名中的Authentitaction应为Authentication,可能导致认证状态通知或依赖注入逻辑异常。
  2. ClaimsIdentity配置缺失:UpdateAuthenticationState方法中创建ClaimsIdentity时未指定认证类型,导致用户身份的IsAuthenticated属性可能为false,即使SessionStorage中存在用户数据。
  3. 认证状态传递缺失:组件未被CascadingAuthenticationState包裹,无法正确获取刷新后的认证状态。
  4. 空引用未防护:业务逻辑未对LoggedUserCode为空的情况做判断,直接访问FirstOrDefault返回的null对象属性,引发空引用异常导致Dapper操作崩溃。

解决方案步骤

1. 修正自定义认证状态提供者的拼写与配置

将类名、方法名的拼写错误修正,并确保ClaimsIdentity统一指定认证类型:

using Microsoft.AspNetCore.Components.Authorization;
using Microsoft.AspNetCore.Components.Server.ProtectedBrowserStorage;
using System.Security.Claims;
using System.Collections.Generic;

namespace VikkingWebApp.Authentication
{
    // 修正类名拼写
    public class CustomAuthenticationStateProvider : AuthenticationStateProvider
    {
        private readonly ProtectedSessionStorage _sessionStorage;
        private ClaimsPrincipal _anonymous = new ClaimsPrincipal(new ClaimsIdentity());

        public CustomAuthenticationStateProvider(ProtectedSessionStorage sessionStorage)
        {
            _sessionStorage = sessionStorage;
        }

        public override async Task<AuthenticationState> GetAuthenticationStateAsync()
        {
            try
            {
                var userSessionStorageResult = await _sessionStorage.GetAsync<UserSession>("UserSession");
                var userSession = userSessionStorageResult.Success ? userSessionStorageResult.Value : null;
                
                if (userSession == null)
                    return new AuthenticationState(_anonymous);
                    
                var claimsPrincipal = new ClaimsPrincipal(new ClaimsIdentity(new List<Claim>
                {
                    new Claim(ClaimTypes.Name, userSession.UserCode),
                    new Claim(ClaimTypes.Role, userSession.Role)
                }, "CustomAuth"));
                
                return new AuthenticationState(claimsPrincipal);
            }
            catch
            {
                return new AuthenticationState(_anonymous);
            }
        }

        // 修正方法名拼写,并添加认证类型
        public async Task UpdateAuthenticationState(UserSession userSession)
        {
            ClaimsPrincipal claimsPrincipal;

            if (userSession != null)
            {
                await _sessionStorage.SetAsync("UserSession", userSession);
                claimsPrincipal = new ClaimsPrincipal(new ClaimsIdentity(new List<Claim>
                {
                    new Claim(ClaimTypes.Name, userSession.UserCode),
                    new Claim(ClaimTypes.Role, userSession.Role)
                }, "CustomAuth")); // 统一认证类型,确保IsAuthenticated为true
            }
            else
            {
                await _sessionStorage.DeleteAsync("UserSession");
                claimsPrincipal = _anonymous;
            }

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

同时更新Program.cs中的服务注册:

builder.Services.AddScoped<ProtectedSessionStorage>();
builder.Services.AddScoped<AuthenticationStateProvider, CustomAuthenticationStateProvider>();

2. 确保全局传递认证状态

在App.razor中用CascadingAuthenticationState包裹路由组件,让所有子组件能获取到认证状态:

<CascadingAuthenticationState>
    <Router AppAssembly="@typeof(App).Assembly">
        <Found Context="routeData">
            <RouteView RouteData="@routeData" DefaultLayout="@typeof(MainLayout)" />
            <FocusOnNavigate RouteData="@routeData" Selector="h1" />
        </Found>
        <NotFound>
            <PageTitle>Not found</PageTitle>
            <LayoutView Layout="@typeof(MainLayout)">
                <p role="alert">Sorry, there's nothing at this address.</p>
            </LayoutView>
        </NotFound>
    </Router>
</CascadingAuthenticationState>

3. 修正组件中认证状态的获取逻辑

在组件中通过CascadingParameter注入认证状态任务,并完善空值防护:

using Microsoft.AspNetCore.Components.Authorization;

// 组件中添加CascadingParameter
[CascadingParameter]
private Task<AuthenticationState> AuthenticationStateTask { get; set; }

private string LoggedUserCode { get; set; }
private User user1 = new User(); // 替换为你的实体类

private async Task LogUsername()
{
    var authState = await AuthenticationStateTask;
    var user = authState.User;

    LoggedUserCode = user.Identity.IsAuthenticated ? user.Identity.Name : null;
}

protected override async Task OnInitializedAsync()
{
    await LogUsername();

    // 多层空值防护,避免空引用
    if (!string.IsNullOrEmpty(LoggedUserCode))
    {
        var matchedUser = Authentication.UserAccountService._users.FirstOrDefault(x => x.Kod == LoggedUserCode);
        if (matchedUser != null)
        {
            user1.Id = matchedUser.Id;
            // 移除不必要的Task.Run,Blazor异步方法无需额外包装
            element = await adminPanels.GetUser(user1.Id);
            mg = await wS.GetWarehouse(element.magazyn);
            // okuciaObj = await VikkingOkucia.PobierzOkucia(mg.id);
        }
    }

    _table?.SetEditingItem(null);
}

4. 业务逻辑空值防护

确保所有依赖用户身份的操作都先检查用户是否已认证、数据是否存在,避免空引用异常导致Dapper操作崩溃。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.22 16:05:11