如何在.NET Core+EF Core中实现高性能行级数据授权?
.NET Core + EF Core 高性能行级数据授权实现方案
需求概述
需要在.NET Core + EF Core环境下实现车辆表的行级数据授权,核心要求:
- 支持多粒度授权规则(单车辆ID、车型、品牌、反向排除等)
- 适配数百万条车辆数据、数百用户的规模
- 优先保证查询性能
场景说明
车辆表结构
| VehicleId | Make | Model | Color |
|---|---|---|---|
| 1 | Audi | A1 | White |
| 2 | Audi | A1 | Blue |
| 3 | Audi | A1 | Orange |
| 4 | Audi | A2 | White |
| 5 | Audi | A2 | Blue |
| 6 | Audi | A2 | Orange |
授权需求示例
- User1:仅可访问VehicleId为5、6的车辆
- User2:仅可访问Model为A1的车辆
- User3:仅可访问Model为A2的车辆
- User4:仅可访问Make为Audi的车辆
- User5:仅可访问非Audi品牌的车辆
最优方案设计
1. 分层权限组模型
通过权限组实现授权规则的复用与批量管理,避免给每个用户单独配置重复规则:
- 精确ID组:存储用户/组与车辆ID的关联关系,适配User1这类指定具体车辆的场景
- 属性过滤组:存储统一的过滤规则(如
Model='A1'、Make='Audi'),适配User2-4这类按属性授权的场景 - 反向排除组:存储排除规则(如
Make!='Audi'),适配User5这类反向授权的场景
2. EF Core 代码实现
权限上下文封装
封装当前用户的权限信息,避免查询中重复获取:
public class UserPermissions { public int UserId { get; set; } public bool HasExactVehicleIds { get; set; } public List<int> AuthorizedVehicleIds { get; set; } = new(); public bool HasModelFilter { get; set; } public string AuthorizedModel { get; set; } public bool HasMakeFilter { get; set; } public string AuthorizedMake { get; set; } public bool HasExclusionFilter { get; set; } }
查询授权扩展方法
编写通用扩展方法,在所有车辆查询前自动应用权限过滤:
public static class VehicleQueryExtensions { public static IQueryable<Vehicle> ApplyAuthorization(this IQueryable<Vehicle> query, UserPermissions permissions) { if (permissions.HasExactVehicleIds) { // 大量ID场景优先用Join,避免超长IN语句 query = from v in query join authorizedId in permissions.AuthorizedVehicleIds on v.VehicleId equals authorizedId select v; } else if (permissions.HasModelFilter) { query = query.Where(v => v.Model == permissions.AuthorizedModel); } else if (permissions.HasMakeFilter) { query = query.Where(v => v.Make == permissions.AuthorizedMake); } else if (permissions.HasExclusionFilter) { query = query.Where(v => v.Make != "Audi"); } return query; } }
业务层使用
在业务逻辑中直接调用扩展方法,无需重复编写过滤逻辑:
public async Task<List<Vehicle>> GetAuthorizedVehicles(UserPermissions currentUserPerms) { using var dbContext = new VehicleDbContext(); return await dbContext.Vehicles .ApplyAuthorization(currentUserPerms) .ToListAsync(); }
3. 性能优化要点
数据库索引优化
针对核心过滤字段创建索引:
- 精确ID场景:给
VehicleId创建唯一索引,GroupVehicleAuthorizations表给GroupId+VehicleId创建组合索引 - 属性过滤场景:给
Make+Model创建组合索引,满足多维度过滤需求
权限规则缓存
将用户的权限规则缓存到内存或Redis中:
- 缓存Key:
UserPermissions_{UserId} - 缓存过期时间:根据权限更新频率设置(如1小时),权限变更时主动刷新缓存
避免低效查询
- 授权车辆ID数量超过1000时,优先使用
Join而非Contains - 使用EF Core的
Select投影只查询需要的字段,减少数据传输量
4. 权限存储表设计
-- 用户组表:存储权限规则 CREATE TABLE UserGroups ( GroupId INT PRIMARY KEY IDENTITY, GroupName NVARCHAR(50) NOT NULL, FilterType NVARCHAR(20) NOT NULL CHECK (FilterType IN ('ExactIds','ModelFilter','MakeFilter','Exclusion')), FilterValue NVARCHAR(MAX) NOT NULL ) -- 用户-组关联表 CREATE TABLE UserGroupMembers ( UserId INT NOT NULL, GroupId INT NOT NULL, PRIMARY KEY (UserId, GroupId), FOREIGN KEY (UserId) REFERENCES Users(UserId), FOREIGN KEY (GroupId) REFERENCES UserGroups(GroupId) ) -- 精确ID授权表(组级) CREATE TABLE GroupVehicleAuthorizations ( GroupId INT NOT NULL, VehicleId INT NOT NULL, PRIMARY KEY (GroupId, VehicleId), FOREIGN KEY (GroupId) REFERENCES UserGroups(GroupId), FOREIGN KEY (VehicleId) REFERENCES Vehicles(VehicleId) )
内容的提问来源于stack exchange,提问作者user1887852
相关产品推荐
相关产品推荐

