基于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
基础仓储接口设计
定义基础仓储接口,包含数据权限过滤方法:- public interface IRepository<T> where T : class
- {
- IQueryable<T> GetAll();
- IQueryable<T> GetByDepartment(int departmentId);
- IQueryable<T> GetByDepartmentWithChildren(int departmentId);
- IQueryable<T> GetByUser(int userId);
- }
复制代码 实现数据权限过滤
在具体仓储实现中,通过EFCore的查询表达式实现不同级别的数据过滤:- public class Repository<T> : IRepository<T> where T : class, IDataPermission
- {
- private readonly DbContext _context;
- private readonly ICurrentUser _currentUser;
- public Repository(DbContext context, ICurrentUser currentUser)
- {
- _context = context;
- _currentUser = currentUser;
- }
- public IQueryable<T> GetAll()
- {
- return _context.Set<T>().AsQueryable();
- }
- public IQueryable<T> GetByDepartment(int departmentId)
- {
- return _context.Set<T>().Where(x => x.DepartmentId == departmentId);
- }
- public IQueryable<T> GetByDepartmentWithChildren(int departmentId)
- {
- var departmentIds = GetChildDepartmentIds(departmentId);
- return _context.Set<T>().Where(x => departmentIds.Contains(x.DepartmentId));
- }
- public IQueryable<T> GetByUser(int userId)
- {
- return _context.Set<T>().Where(x => x.CreatedBy == userId);
- }
- private List<int> GetChildDepartmentIds(int parentId)
- {
- // 递归获取所有子部门ID
- }
- }
复制代码 实体接口设计
定义数据权限相关实体接口,确保实体包含必要字段:- public interface IDataPermission
- {
- int DepartmentId { get; set; }
- int CreatedBy { get; set; }
- }
复制代码 动态权限查询扩展
创建扩展方法,根据用户权限动态选择查询范围:- public static class RepositoryExtensions
- {
- public static IQueryable<T> WithDataPermission<T>(this IRepository<T> repository, DataPermissionLevel level)
- where T : class, IDataPermission
- {
- switch(level)
- {
- case DataPermissionLevel.All:
- return repository.GetAll();
- case DataPermissionLevel.Department:
- return repository.GetByDepartment(currentUser.DepartmentId);
- case DataPermissionLevel.DepartmentWithChildren:
- return repository.GetByDepartmentWithChildren(currentUser.DepartmentId);
- case DataPermissionLevel.Owner:
- return repository.GetByUser(currentUser.UserId);
- default:
- throw new ArgumentOutOfRangeException();
- }
- }
- }
复制代码 权限枚举定义
定义数据权限级别枚举:- public enum DataPermissionLevel
- {
- All,
- Department,
- DepartmentWithChildren,
- Owner
- }
复制代码 使用示例
在服务层或控制器中使用数据权限过滤:- public class EmployeeService
- {
- private readonly IRepository<Employee> _repository;
- private readonly ICurrentUser _currentUser;
- public EmployeeService(IRepository<Employee> repository, ICurrentUser currentUser)
- {
- _repository = repository;
- _currentUser = currentUser;
- }
- public List<Employee> GetEmployees(DataPermissionLevel level)
- {
- return _repository.WithDataPermission(level).ToList();
- }
- }
复制代码 权限控制中间件
可以创建中间件自动设置当前用户的数据权限级别:- public class DataPermissionMiddleware
- {
- private readonly RequestDelegate _next;
- public DataPermissionMiddleware(RequestDelegate next)
- {
- _next = next;
- }
- public async Task InvokeAsync(HttpContext context, ICurrentUser currentUser)
- {
- // 根据用户角色设置数据权限级别
- currentUser.DataPermissionLevel = GetPermissionLevelFromClaims(context.User);
-
- await _next(context);
- }
- }
复制代码 这种实现方式通过仓储模式统一了数据权限控制逻辑,使业务代码无需关心具体权限实现细节,只需指定权限级别即可自动过滤数据。
来源:程序园用户自行投稿发布,如果侵权,请联系站长删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作! |