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
相关产品推荐
相关产品推荐

