.Net通过EFCore和仓储模式实现统一数据权限管控并且相关权限配置动态生成

基于EFCore实现统一数据权限管控

在.NET应用中,通过EFCore和仓储模式实现数据权限管控,可以按照以下方式设计:

数据权限层级定义

数据权限通常分为四个层级:所有数据、本部门数据、本部门及下属部门数据、本人数据。通过仓储模式可以统一封装这些查询逻辑。

具体实现可参考NetCoreKevin的Kevin.EntityFrameworkCore.Repository`和kevin.Permission服务模块:实现统一数据权限管控并且相关权限配置动态生成

基于NET构建的现代化AI智能体Saas企业级架构: 项目地址:github:github.com/junkai-li/N... Gitee: gitee.com/netkevin-li...

基础仓储接口设计

定义基础仓储接口,包含数据权限过滤方法:

csharp 复制代码
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的查询表达式实现不同级别的数据过滤:

csharp 复制代码
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
    }
}

实体接口设计

定义数据权限相关实体接口,确保实体包含必要字段:

csharp 复制代码
public interface IDataPermission
{
    int DepartmentId { get; set; }
    int CreatedBy { get; set; }
}

动态权限查询扩展

创建扩展方法,根据用户权限动态选择查询范围:

csharp 复制代码
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();
        }
    }
}

权限枚举定义

定义数据权限级别枚举:

csharp 复制代码
public enum DataPermissionLevel
{
    All,
    Department,
    DepartmentWithChildren,
    Owner
}

使用示例

在服务层或控制器中使用数据权限过滤:

csharp 复制代码
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();
    }
}

权限控制中间件

可以创建中间件自动设置当前用户的数据权限级别:

csharp 复制代码
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);
    }
}

这种实现方式通过仓储模式统一了数据权限控制逻辑,使业务代码无需关心具体权限实现细节,只需指定权限级别即可自动过滤数据。

相关推荐
晴栀ay36 分钟前
Generator + RxJS 重构 LLM 流式输出的“丝滑”架构
javascript·后端·llm
下次一定x40 分钟前
深度解析 Kratos 客户端服务发现与负载均衡:从 Dial 入口到 gRPC 全链路落地(下篇)
后端·go
彭于晏Yan2 小时前
SpringBoot整合ECC实现文件签名与验签
java·spring boot·后端
pupudawang2 小时前
Spring EL 表达式的简单介绍和使用
java·后端·spring
coderYYY2 小时前
git push报错Authentication failed for ‘xxx’也不会弹要求输入用户名密码的最终解决方法
前端·git·gitee·github
xianjian09122 小时前
springboot与springcloud以及springcloudalibaba版本对照
spring boot·后端·spring cloud
羊小猪~~2 小时前
【QT】-- QMainWindow简介
开发语言·数据库·c++·后端·qt·前端框架·求职招聘
ruxingli3 小时前
GoLang的并发如何避免死锁
开发语言·后端·golang
Tyooughtul3 小时前
MySQL篇 索引失效
后端
YMWM_3 小时前
python3中的装饰器介绍及其应用场景
java·后端·spring