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

Microsoft Blazor基于用户团队的授权实现方案咨询

基于团队的Blazor权限控制实现方案

核心思路:通用过滤逻辑封装 + 分层复用

针对所有继承IUser的实体,将团队过滤逻辑抽象为可复用组件,避免在每个Get方法中重复编码。以下是具体实现步骤:

1. 封装通用权限过滤服务

创建专注于权限过滤的服务,统一处理团队权限逻辑,支持EF Core表达式树查询(确保能被EF解析转为SQL)。

public interface IPermissionFilterService
{
    // 针对实现IUser的实体,返回对应的过滤表达式
    Expression<Func<T, bool>> GetTeamFilter<T>() where T : class, IUser;
}

public class PermissionFilterService : IPermissionFilterService
{
    private readonly ICurrentUserService _currentUserService;
    private readonly AppDbContext _dbContext;

    public PermissionFilterService(ICurrentUserService currentUserService, AppDbContext dbContext)
    {
        _currentUserService = currentUserService;
        _dbContext = dbContext;
    }

    public Expression<Func<T, bool>> GetTeamFilter<T>() where T : class, IUser
    {
        var currentUser = _currentUserService.GetCurrentUser();
        
        // Admin用户直接返回全部数据的过滤条件
        if (currentUser.IsAdmin)
        {
            return entity => true;
        }

        // Member用户:仅显示当前用户团队内成员创建的数据
        return entity => _dbContext.Users
            .Any(u => u.Id == entity.reference_user_id && u.TeamId == currentUser.TeamId);
    }
}

// 辅助服务:获取当前登录用户信息(根据Blazor Server/WASM调整实现)
public interface ICurrentUserService
{
    User GetCurrentUser();
}

2. EF Core全局查询过滤(可选,全实体统一生效)

如果用EF Core作为ORM,可为所有IUser实体添加全局查询过滤,从数据访问层自动生效,无需在服务层重复调用。

public class AppDbContext : DbContext
{
    private readonly IPermissionFilterService _permissionFilterService;

    public AppDbContext(DbContextOptions<AppDbContext> options, IPermissionFilterService permissionFilterService)
        : base(options)
    {
        _permissionFilterService = permissionFilterService;
    }

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        base.OnModelCreating(modelBuilder);

        // 遍历所有实现IUser的实体类型,添加全局过滤
        foreach (var entityType in modelBuilder.Model.GetEntityTypes())
        {
            if (typeof(IUser).IsAssignableFrom(entityType.ClrType))
            {
                var filterMethod = typeof(IPermissionFilterService)
                    .GetMethod(nameof(IPermissionFilterService.GetTeamFilter))
                    .MakeGenericMethod(entityType.ClrType);
                
                var filterExpression = (LambdaExpression)filterMethod.Invoke(_permissionFilterService, null);
                modelBuilder.Entity(entityType.ClrType).HasQueryFilter(filterExpression);
            }
        }
    }
}

3. 服务层通用基类(避免重复编码)

创建通用服务基类,封装基础CRUD方法并自动应用权限过滤,各实体服务只需继承该基类即可。

public class GenericService<T> : IGenericService<T> where T : class, IUser
{
    protected readonly AppDbContext _dbContext;
    protected readonly IPermissionFilterService _permissionFilterService;
    protected readonly DbSet<T> _dbSet;

    public GenericService(AppDbContext dbContext, IPermissionFilterService permissionFilterService)
    {
        _dbContext = dbContext;
        _permissionFilterService = permissionFilterService;
        _dbSet = dbContext.Set<T>();
    }

    public async Task<List<T>> GetAllAsync()
    {
        var filter = _permissionFilterService.GetTeamFilter<T>();
        return await _dbSet.Where(filter).ToListAsync();
    }

    public async Task<T> GetByIdAsync(int id)
    {
        var filter = _permissionFilterService.GetTeamFilter<T>();
        return await _dbSet.Where(filter).FirstOrDefaultAsync(e => e.Id == id);
    }

    // 其他CRUD方法按需实现...
}

// DataSetting实体服务直接继承通用基类
public class DataSettingService : GenericService<DataSetting>, IDataSettingService
{
    public DataSettingService(AppDbContext dbContext, IPermissionFilterService permissionFilterService)
        : base(dbContext, permissionFilterService)
    {
    }

    // 自定义方法如需过滤,同样调用GetTeamFilter<T>即可
}

4. 控制器与Blazor组件层的使用

  • 控制器:注入对应实体服务,直接调用方法即可,权限过滤已在服务层自动处理:
[ApiController]
[Route("api/[controller]")]
public class DataSettingController : ControllerBase
{
    private readonly IDataSettingService _dataSettingService;

    public DataSettingController(IDataSettingService dataSettingService)
    {
        _dataSettingService = dataSettingService;
    }

    [HttpGet]
    public async Task<IActionResult> GetAll()
    {
        var data = await _dataSettingService.GetAllAsync();
        return Ok(data);
    }
}
  • Blazor组件:注入服务后直接获取数据,无需额外处理过滤:
@inject IDataSettingService DataSettingService

@foreach(var item in DataSettings)
{
    <p>@item.Name</p>
}

@code {
    private List<DataSetting> DataSettings { get; set; }

    protected override async Task OnInitializedAsync()
    {
        DataSettings = await DataSettingService.GetAllAsync();
    }
}

关键注意事项

  • 当前用户信息获取:Blazor Server可通过IHttpContextAccessor获取用户Claims,WASM则通过AuthenticationStateProvider,需根据项目类型实现ICurrentUserService。
  • 全局过滤例外场景:若某些业务需绕过权限过滤,可在DbContext中使用IgnoreQueryFilters(),但需谨慎操作。
  • 性能优化:确保User.TeamId、IUser.reference_user_id字段已添加数据库索引,避免关联查询性能问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.20 10:52:09