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

Blazor Server中基于角色/权限的授权实现问题求助

Blazor Server 角色&权限访问控制解决方案

核心思路

基于自定义AppUserContext存储用户角色与权限,替代依赖HttpContext的传统授权体系,分别实现页面级角色管控、组件级权限管控、服务端方法权限校验。


1. 定义用户上下文服务

创建Scoped服务存储当前用户的角色与权限,认证时从数据库加载数据:

public class AppUserContext
{
    public string UserId { get; set; }
    public List<string> Roles { get; set; } = new();
    public List<string> Permissions { get; set; } = new();

    // 角色校验
    public bool IsInRole(string role) 
        => Roles.Contains(role, StringComparer.OrdinalIgnoreCase);
    
    // 权限校验
    public bool HasPermission(string permission) 
        => Permissions.Contains(permission, StringComparer.OrdinalIgnoreCase);
}

在Program.cs注册为Scoped服务:

builder.Services.AddScoped<AppUserContext>();

2. 页面级角色授权(替代[Authorize])

创建页面基类,在初始化时校验用户角色,无权限则跳转至未授权页面:

public class AuthorizePageBase : ComponentBase
{
    [Inject] protected AppUserContext UserContext { get; set; }
    [Inject] protected NavigationManager NavigationManager { get; set; }

    [Parameter] public string AllowedRoles { get; set; }

    protected override async Task OnInitializedAsync()
    {
        await base.OnInitializedAsync();

        var allowedRoles = AllowedRoles.Split(',', StringSplitOptions.RemoveEmptyEntries)
                                      .Select(r => r.Trim())
                                      .ToList();

        // 检查是否拥有任一允许角色
        var hasAccess = allowedRoles.Any(role => UserContext.IsInRole(role));
        if (!hasAccess)
        {
            NavigationManager.NavigateTo("/unauthorized");
        }
    }
}

页面使用示例:

@inherits AuthorizePageBase
@{
    AllowedRoles = "SuperAdmin, Auditor, Operator";
}

<!-- 页面内容 -->

3. 实现CustomAuthorizeView组件

创建自定义组件,根据权限控制子内容渲染:

@inject AppUserContext UserContext

@if (HasRequiredPermission)
{
    @ChildContent
}
else
{
    @UnauthorizedContent
}

@code {
    [Parameter] public RenderFragment ChildContent { get; set; }
    [Parameter] public RenderFragment UnauthorizedContent { get; set; }
    [Parameter] public string Permission { get; set; }

    private bool HasRequiredPermission => !string.IsNullOrWhiteSpace(Permission) 
                                          && UserContext.HasPermission(Permission);

    protected override void OnParametersSet()
    {
        base.OnParametersSet();
        if (string.IsNullOrWhiteSpace(Permission))
        {
            throw new ArgumentNullException(nameof(Permission), "权限标识不能为空");
        }
    }
}

组件使用示例(与你的需求完全匹配):

<CustomAuthorizeView Permission="AddUser">
    <div class="radzen-filter">
        <RadzenStack Orientation="Orientation.Horizontal" AlignItems="AlignItems.Center" Gap="0.5rem" Style="margin-bottom: 1rem;">
            <RadzenButton Click="@CreateUser" Text="Add User" Icon="add" ButtonStyle="ButtonStyle.Primary" />
        </RadzenStack>
    </div>
</CustomAuthorizeView>

如需自定义未授权提示:

<CustomAuthorizeView Permission="AddUser">
    <!-- 授权可见内容 -->
    <UnauthorizedContent>
        <p>您没有添加用户的权限</p>
    </UnauthorizedContent>
</CustomAuthorizeView>

4. 服务端方法权限校验

在业务服务中注入AppUserContext,直接校验权限:

public class UserService
{
    private readonly AppUserContext _userContext;

    public UserService(AppUserContext userContext)
    {
        _userContext = userContext;
    }

    public async Task CreateUser(UserDto userDto)
    {
        if (!_userContext.HasPermission("AddUser"))
        {
            throw new UnauthorizedAccessException("无添加用户权限");
        }

        // 业务逻辑实现
    }
}

5. 认证时加载角色与权限

在自定义认证逻辑中,从数据库加载用户角色及关联权限,填充至AppUserContext:

public async Task<bool> AuthenticateAsync(string username, string password)
{
    // 1. 校验用户名密码
    var user = await _userRepo.GetUserByUsernameAsync(username);
    if (user == null || !VerifyPassword(password, user.PasswordHash))
    {
        return false;
    }

    // 2. 加载角色与权限
    var roles = await _roleRepo.GetRolesByUserIdAsync(user.Id);
    var permissions = await _permissionRepo.GetPermissionsByRoleIds(roles.Select(r => r.Id));

    // 3. 填充至用户上下文
    var userContext = _serviceProvider.GetRequiredService<AppUserContext>();
    userContext.UserId = user.Id;
    userContext.Roles = roles.Select(r => r.Name).ToList();
    userContext.Permissions = permissions.Select(p => p.Name).ToList();

    return true;
}

常见问题排查

如果你的示例方案无法运行,优先检查以下几点:

  • AppUserContext是否注册为Scoped服务,且认证时正确填充了角色/权限数据
  • CustomAuthorizeView是否正确注入AppUserContext
  • 角色/权限名称是否与数据库中存储的一致(注意大小写问题)
  • 页面基类的AllowedRoles参数是否正确传递

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.13 18:15:19