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

Blazor Server中ASP.NET Identity实时权限更新与禁用用户校验实现

Blazor Server + ASP.NET Identity 需求实现方案

1. 修改Claims无需登出立即生效

Blazor Server默认的ServerAuthenticationStateProvider会缓存初始登录后的身份信息,要实现Claims实时更新,需自定义身份状态提供者,每次获取身份时从数据库拉取最新Claims:

  • 第一步:创建自定义身份状态提供者
public class CustomAuthStateProvider : ServerAuthenticationStateProvider
{
    private readonly UserManager<ApplicationUser> _userManager;
    private readonly IHttpContextAccessor _httpContextAccessor;

    public CustomAuthStateProvider(UserManager<ApplicationUser> userManager, IHttpContextAccessor httpContextAccessor)
    {
        _userManager = userManager;
        _httpContextAccessor = httpContextAccessor;
    }

    public override async Task<AuthenticationState> GetAuthenticationStateAsync()
    {
        var authState = await base.GetAuthenticationStateAsync();
        var user = authState.User;

        if (user.Identity?.IsAuthenticated == true)
        {
            var appUser = await _userManager.FindByNameAsync(user.Identity.Name);
            if (appUser != null)
            {
                // 重新生成包含最新Claims的身份对象
                var claims = await _userManager.GetClaimsAsync(appUser);
                var newIdentity = new ClaimsIdentity(claims, user.Identity.AuthenticationType);
                var newUser = new ClaimsPrincipal(newIdentity);

                // 更新缓存的身份状态
                SetAuthenticationState(Task.FromResult(new AuthenticationState(newUser)));
                return new AuthenticationState(newUser);
            }
        }

        return authState;
    }

    // 提供主动刷新方法,用于Claims修改后触发前端更新
    public async Task RefreshAuthenticationState()
    {
        NotifyAuthenticationStateChanged(GetAuthenticationStateAsync());
    }
}
  • 第二步:注册自定义Provider
    在Program.cs中替换默认服务:
builder.Services.AddScoped<AuthenticationStateProvider, CustomAuthStateProvider>();
  • 第三步:修改Claims后主动触发刷新
    在后台修改用户Claims的代码后,调用刷新方法通知前端:
// 注入CustomAuthStateProvider后调用
await _customAuthStateProvider.RefreshAuthenticationState();

2. 页面跳转时重新读取Claims(保留登录缓存)

通过监听页面导航事件,每次跳转完成后触发身份状态刷新,既保留登录Cookie缓存,又能重新读取最新Claims:

在MainLayout.razor中注入服务并监听导航事件:

@inject NavigationManager NavigationManager
@inject CustomAuthStateProvider AuthStateProvider
@implements IDisposable

@code {
    protected override void OnInitialized()
    {
        NavigationManager.LocationChanged += OnLocationChanged;
    }

    private async void OnLocationChanged(object sender, LocationChangedEventArgs e)
    {
        // 页面跳转完成后刷新身份状态
        await AuthStateProvider.RefreshAuthenticationState();
    }

    public void Dispose()
    {
        NavigationManager.LocationChanged -= OnLocationChanged;
    }
}

3. 添加Enable列并拦截禁用用户

步骤1:扩展IdentityUser模型

修改自定义用户模型,添加Enable属性:

public class ApplicationUser : IdentityUser
{
    public bool Enable { get; set; } = true; // 默认启用用户
}

步骤2:更新数据库表

创建并执行EF Core迁移,将Enable列添加到AspNetUsers表:

dotnet ef migrations add AddEnableColumnToUsers
dotnet ef database update

步骤3:身份验证时校验启用状态

修改CustomAuthStateProvider的GetAuthenticationStateAsync方法,加入禁用用户校验:

public override async Task<AuthenticationState> GetAuthenticationStateAsync()
{
    var authState = await base.GetAuthenticationStateAsync();
    var user = authState.User;

    if (user.Identity?.IsAuthenticated == true)
    {
        var appUser = await _userManager.FindByNameAsync(user.Identity.Name);
        if (appUser != null)
        {
            // 用户被禁用时返回匿名身份,触发[Authorize]拦截
            if (!appUser.Enable)
            {
                var anonymousUser = new ClaimsPrincipal(new ClaimsIdentity());
                SetAuthenticationState(Task.FromResult(new AuthenticationState(anonymousUser)));
                return new AuthenticationState(anonymousUser);
            }

            // 正常更新Claims逻辑
            var claims = await _userManager.GetClaimsAsync(appUser);
            var newIdentity = new ClaimsIdentity(claims, user.Identity.AuthenticationType);
            var newUser = new ClaimsPrincipal(newIdentity);

            SetAuthenticationState(Task.FromResult(new AuthenticationState(newUser)));
            return new AuthenticationState(newUser);
        }
    }

    return authState;
}

可选:自定义授权特性强化校验

如果需要覆盖更多场景(如API接口),可自定义授权特性:

public class EnableUserAuthorizeAttribute : AuthorizeAttribute
{
    protected override Task HandleUnauthorizedAsync(AuthorizationHandlerContext context)
    {
        var userManager = context.HttpContext.RequestServices.GetRequiredService<UserManager<ApplicationUser>>();
        var user = userManager.GetUserAsync(context.User).Result;
        if (user != null && !user.Enable)
        {
            context.Fail(new AuthorizationFailureReason(this, "用户已被禁用"));
        }
        return base.HandleUnauthorizedAsync(context);
    }
}

使用时将[Authorize]替换为[EnableUserAuthorize]即可。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.17 18:57:37