基于EFCore实现统一数据权限管控
在.NET应用中,通过EFCore和仓储模式实现数据权限管控,可以按照以下方式设计:
数据权限层级定义
数据权限通常分为四个层级:所有数据、本部门数据、本部门及下属部门数据、本人数据。通过仓储模式可以统一封装这些查询逻辑。
具体实现可参考NetCoreKevin的Kevin.EntityFrameworkCore.Repository`和kevin.Permission服务模块:实现统一数据权限管控并且相关权限配置动态生成
基于NET构建的现代化AI智能体Saas企业级架构:
项目地址:github:https://github.com/junkai-li/NetCoreKevin
Gitee: https://gitee.com/netkevin-li/NetCoreKevin
基础仓储接口设计
定义基础仓储接口,包含数据权限过滤方法:
publicinterfaceIRepository<T>whereT:class{IQueryable<T>GetAll();IQueryable<T>GetByDepartment(intdepartmentId);IQueryable<T>GetByDepartmentWithChildren(intdepartmentId);IQueryable<T>GetByUser(intuserId);}实现数据权限过滤
在具体仓储实现中,通过EFCore的查询表达式实现不同级别的数据过滤:
publicclassRepository<T>:IRepository<T>whereT:class,IDataPermission{privatereadonlyDbContext_context;privatereadonlyICurrentUser_currentUser;publicRepository(DbContextcontext,ICurrentUsercurrentUser){_context=context;_currentUser=currentUser;}publicIQueryable<T>GetAll(){return_context.Set<T>().AsQueryable();}publicIQueryable<T>GetByDepartment(intdepartmentId){return_context.Set<T>().Where(x=>x.DepartmentId==departmentId);}publicIQueryable<T>GetByDepartmentWithChildren(intdepartmentId){vardepartmentIds=GetChildDepartmentIds(departmentId);return_context.Set<T>().Where(x=>departmentIds.Contains(x.DepartmentId));}publicIQueryable<T>GetByUser(intuserId){return_context.Set<T>().Where(x=>x.CreatedBy==userId);}privateList<int>GetChildDepartmentIds(intparentId){// 递归获取所有子部门ID}}实体接口设计
定义数据权限相关实体接口,确保实体包含必要字段:
publicinterfaceIDataPermission{intDepartmentId{get;set;}intCreatedBy{get;set;}}动态权限查询扩展
创建扩展方法,根据用户权限动态选择查询范围:
publicstaticclassRepositoryExtensions{publicstaticIQueryable<T>WithDataPermission<T>(thisIRepository<T>repository,DataPermissionLevellevel)whereT:class,IDataPermission{switch(level){caseDataPermissionLevel.All:returnrepository.GetAll();caseDataPermissionLevel.Department:returnrepository.GetByDepartment(currentUser.DepartmentId);caseDataPermissionLevel.DepartmentWithChildren:returnrepository.GetByDepartmentWithChildren(currentUser.DepartmentId);caseDataPermissionLevel.Owner:returnrepository.GetByUser(currentUser.UserId);default:thrownewArgumentOutOfRangeException();}}}权限枚举定义
定义数据权限级别枚举:
publicenumDataPermissionLevel{All,Department,DepartmentWithChildren,Owner}使用示例
在服务层或控制器中使用数据权限过滤:
publicclassEmployeeService{privatereadonlyIRepository<Employee>_repository;privatereadonlyICurrentUser_currentUser;publicEmployeeService(IRepository<Employee>repository,ICurrentUsercurrentUser){_repository=repository;_currentUser=currentUser;}publicList<Employee>GetEmployees(DataPermissionLevellevel){return_repository.WithDataPermission(level).ToList();}}权限控制中间件
可以创建中间件自动设置当前用户的数据权限级别:
publicclassDataPermissionMiddleware{privatereadonlyRequestDelegate_next;publicDataPermissionMiddleware(RequestDelegatenext){_next=next;}publicasyncTaskInvokeAsync(HttpContextcontext,ICurrentUsercurrentUser){// 根据用户角色设置数据权限级别currentUser.DataPermissionLevel=GetPermissionLevelFromClaims(context.User);await_next(context);}}这种实现方式通过仓储模式统一了数据权限控制逻辑,使业务代码无需关心具体权限实现细节,只需指定权限级别即可自动过滤数据。