权限控制模型
在一个健壮的系统中 权限控制是必不可少的一个环节 什么用户可以访问什么内容 什么用户可以修改什么内容 这些都是需要严格控制清楚的 在接触的几个项目中 鱼皮是直接在前端进行鉴权 林陌是在controller中加上public、private、protected来进行鉴权 但总感觉有些不妥 于是又了解到了一些关于权限控制的模型 比如rbac、abac、pbac、dac、mac等等 下面对这些概念做个系统了解 权衡之后再做深入学习
权限控制的方法:
前端鉴权(基于路由的权限控制)
这种方法常见于前端框架中,特别是在 单页应用(SPA) 中。 前端会根据用户的角色或权限决定哪些路由可以访问,哪些路由需要隐藏。 例如,前端路由配置中可能会判断用户是否拥有某个角色或权限,若没有则禁用某个页面的跳转或直接隐藏某些组件。
优点:
- 快速响应:前端做了权限控制,用户体验较好,能够快速进行路由跳转判断。
- 减少后端负担:前端可以减少不必要的请求,避免后端压力过大。
缺点:
- 不安全:前端控制的权限是完全可以绕过的,用户可以通过修改浏览器的开发者工具来修改角色或绕过控制。因此,前端鉴权只能作为用户体验的一部分,而不能作为安全控制的主要手段。
- 冗余:不同的前端组件或页面需要重复进行权限判断,可能造成冗余代码。
专业术语:
- 客户端访问控制:此方法属于客户端(前端)进行权限控制,虽然可以提供简单的UI交互控制,但不应被视为安全模型。
ACL(Access Control Lists,访问控制列表)
通过路径和接口的设计,ACL 可以视为这种方式的一种实现。 ACL 以列表的形式定义了哪些用户或角色可以访问哪些资源。
接口通过URL路径进行不同权限的控制,如/public/friends 和 /protected/friends,这实际上是在控制器级别对接口进行访问控制,可能是通过一些简单的设计来标识某些接口是公开的或需要权限的。这种方式通过接口设计(如路径、方法等)来区分权限的级别。
优点:
- 更加安全:后端鉴权相对更安全,因为用户无法直接修改后端代码或路径。权限控制通过服务端的业务逻辑来处理,能够确保接口的访问符合权限要求。
- 易于集中管理:后端权限可以集中管理,所有的权限控制逻辑都集中在后端代码中,便于维护和审计。
缺点:
- 冗余代码:如果权限控制非常基础(比如通过
public、protected来做判断),则可能导致开发过程中的代码重复,尤其是接口的细粒度控制、权限标识等容易成为重复的工作。 - 不够灵活:这种方法可能限制了前端的灵活性,不能针对每个用户的个性化需求做精细控制。
RBAC(Role-Based Access Control,基于角色的访问控制)
RBAC 是最常见的权限控制模型之一。它的核心思想是:通过为用户分配角色来控制用户的权限。每个角色有一组权限,用户通过其角色来继承权限。
RBAC的层级模型:
- RBAC0:最基础的RBAC模型,用户通过角色获得权限。
- RBAC1:在RBAC0的基础上引入了继承的概念,即角色可以继承其他角色的权限。例如,
VIP角色可以继承User角色的权限。 - RBAC2:在RBAC1的基础上,引入了约束(Constraints)的概念,进一步细化角色之间的关系。例如,一个
Admin角色只能授权给某些特定用户。 - RBAC3:在RBAC2的基础上,可以添加权限约束,例如指定某个角色只能在特定时间段内执行某个操作。
优点:
- 简单易用:根据角色来组织权限,非常直观。
- 适用广泛:适合组织结构较为简单、用户和角色比较固定的应用场景。
缺点:
- 灵活性差:只能按角色进行权限分配,无法根据其他用户特征(如属性)进行细粒度控制。
- 权限过度授权:角色可能会有过多权限,难以做到最小权限原则。
- 扩展性:规模较小时拓展性还不错,只需要加几个角色;当系统规模变大,需要更加细粒度的控制时,RBAC可能难以适应。
适用场景:
- 中小型企业内部系统,团队合作型应用,系统结构较为简单的应用。
ABAC(Attribute-Based Access Control,基于属性的访问控制)
ABAC 是一种更加灵活的权限控制模型,它不局限于角色,还可以基于用户的属性(如身份、角色、所在部门等)、资源的属性(如资源类型、数据敏感性)以及环境的属性(如访问时间、IP地址等)来决定是否授予访问权限。
优点:
- 灵活性强:可以结合多个属性进行精细化的访问控制。
- 细粒度控制:支持动态决策,能够根据具体情况灵活授权。
缺点:
- 复杂性高:需要定义和管理大量的属性和规则,系统复杂度较高。
- 性能问题:鉴权过程可能比较耗时,因为需要对多个属性和规则进行评估。
适用场景:
- 大型企业,云平台,细粒度控制非常重要的场景(如医疗、金融、政府等需要严格保密的行业)。
DAC(Discretionary Access Control,自愿访问控制)
DAC 是一种灵活性较高的权限控制模型,其中资源的所有者决定是否授权其他用户访问其资源。也就是说,权限由资源的拥有者(如文件所有者)来控制。
优点:
- 灵活性高:资源所有者可以自由决定哪些用户可以访问资源。
- 简单易实现:对于小规模的系统或文件管理系统来说,DAC方法实现较为简单。
缺点:
- 安全性差:由于资源的拥有者可以随意授予权限,容易导致权限滥用或未授权访问。
- 不易管理:当系统用户量增加时,权限管理的复杂度也会显著增加。
适用场景:
- 适用于小型系统,或者文件系统、数据库管理等需要单独文件/资源管理的场景。
MAC(Mandatory Access Control,强制访问控制)
MAC 是一种高度严格的权限控制模型,它的核心思想是,所有的权限控制都是由系统管理员定义的,用户和资源所有者无法自行改变权限。系统会根据每个对象的标签(如敏感度、机密级别等)和用户的安全标签(如安全级别、授权状态)来判断是否授予访问权限。
优点:
- 安全性高:由于权限由系统统一管理,避免了权限滥用的风险,适用于高安全性需求的场景。
- 强制性控制:严格控制每个用户和资源的访问行为。
缺点:
- 灵活性差:用户和资源拥有者不能修改权限,管理起来比较复杂。
- 复杂的策略管理:系统管理员需要精细化设计所有的权限规则,管理成本较高。
适用场景:
- 军事、政府、银行等高安全需求的行业,需要对信息安全进行严格控制的场合。
PBAC(Policy-Based Access Control,基于策略的访问控制)
PBAC 是一种灵活且基于策略的权限控制模型,结合了ABAC和RBAC的特点。管理员通过定义访问策略来决定谁可以访问哪些资源。访问策略通常是基于角色、用户属性、资源属性等多种条件。
优点:
- 灵活且可扩展:支持动态策略和复杂的访问决策,能够灵活应对各种场景。
- 易于管理:集中管理策略,适用于大规模企业系统。
缺点:
- 需要细致的策略设计:策略设计和维护可能非常复杂,尤其是当策略数量增多时。
- 可能存在性能问题:复杂的访问策略可能会导致鉴权过程变慢。
- 相对较新,应用不广泛:PBAC相较于RBAC和ABAC的成熟度较低,且没有广泛的支持库和框架。
适用场景:
- 大规模的企业应用系统,需要根据多个条件动态调整权限的场景。
可以借鉴文章: 浅析权限管理模型(DAC, MAC, RBAC, ABAC) 【安全】技术干货 | 基于PBAC模型构建零信任IAM平台 权限设计种类【RBAC、ABAC】
如何选择
首先前端鉴权肯定安全性不能得到保证 可以存在 但不能仅依赖前端进行鉴权 所以不作考虑
然后controller中使用ACL分配 可拓展性太落 拘泥过多 不作考虑
rbac确实是看到了很多便利之处 再使用上其rbac1中继承的概念 就可以很方便实现比如vip用户继承于普通用户这样的设计 其实很符合大部分业务逻辑 但缺点也显而易见 权限全都依赖于role的设计 但role必然不会设计的很多 这也就导致权限的控制比较粗粒度 如果项目变得比较庞大 需要对系统内部人员也进行鉴权 比如涉及模块1的员工只能授予相应模块的访问权限 这样的话 仅仅依靠一个管理员role是无法做到的 所以这时候就需要abac来进行较为细粒度的鉴权处理 但这也是后话 是否一开始就使用rbac与abac的结合体pbac? 但我在网络上并没有搜索到关于它的较多内容 可能是还没有大规模的使用上 不算很成熟吧应该是 既然是在学习阶段 就没必要去硬着头皮脱离市场去做那第一个吃螃蟹的人 目前来说 对于现在的项目需求 rbac是足够满足的 哪怕是一些大项目内部的鉴权 也可以通过资源分组的方式来实现: 例如,可以为不同的资源分组设置类似层级的角色: 普通用户 模块管理员(对特定模块的管理访问) 系统管理员(全局权限) 通过这种分组和继承机制,可以在一定程度上提高RBAC模型的灵活性,同时减少粗粒度带来的问题。
ABAC虽然灵活,但确实由于依赖规则的制定可能过于复杂。为降低复杂性,可以事先设计一个标准化的规则模板框架,例如: 用户属性:Department=HR && Role=Manager 资源属性:ResourceType=Confidential && SensitivityLevel=High 环境属性:AccessTime=09:00~18:00 && IP=Internal 通过模板统一规则的表达形式和设计标准,可以降低初次部署时规则复杂性对系统可用性的影响。
适配PBAC的渐进式实施 PBAC作为ABAC和RBAC的融合,是未来权限控制的一种方向,尽管目前成熟度不够高。在实际中,可以从RBAC逐步过渡到PBAC,将关键逻辑和静态角色先保留为RBAC结构,然后新增基于属性的动态策略,逐步强化权限控制的灵活性。 关于结合模型的使用建议 RBAC和ABAC的结合实际上是目前较为实用的方式,“RBAC+ABAC的结合”思路可以采用以下方式逐步落地: 核心权限用RBAC实现:主要权限逻辑(如页面访问权限、功能权限)基于角色设计。 细粒度权限用ABAC增强:对具体模块(如特定数据的访问)动态增加属性条件进行限制,比如“仅允许经理角色且属下员工数量大于10时访问某数据”。
总之 短期选择RBAC:当前系统规模较小时,RBAC的实现成本低,更容易落地,适合满足大部分中小型项目的需求。 扩展建议:为避免将来RBAC难以满足更大规模项目的需求,在设计角色/资源分组时可以预留一定的扩展性。例如,提前为ABAC扩展预留接口。 长期目标向ABAC过渡:当系统扩大并且对权限细粒度要求增多,可以考虑渐进地向ABAC的方式过渡,用动态的规则补充RBAC的角色模型。 示例实现方式:结合ABAC的思想在RBAC中增加规则条件检查,比如在操作某模块的数据时,检查用户属性(例如部门、等级等)。 逐步兼容PBAC:如果未来PBAC生态更加成熟,完全可以基于目前的RBAC+ABAC实现,逐步迁移到PBAC模型中。 注意事项:PBAC的性能依赖于策略引擎,选择合适的技术栈(如Policy Engine)将是关键。
如何设计Rbac模型
认证流程:
三重校验 首先无需登录就能访问的页面(role:游客 该身份无需定义 因为无需注册无需写入数据库) 其次是需要登录才能访问的页面或者执行的功能(如点赞评论) (role:普通用户) 接下来是对身份的验证 如访问比较高级的页面或功能(如访问某些付费内容)(role:vip用户) 访问管理后台(role:管理员)
表的设计:
首先从用户表中衍生出角色表 角色与用户之间需要一个user_role表进行关联 角色拥有哪些权限 这需要一张权限表 同理需要一个role_permission 所以要设计出pbac模型 至少需要五张表 user role user_role permission role_permission
之后系统扩充 对权限的细化 可能还需要引入用户组 对于权限中包含哪些操作的细化 又需要引入几个表
这里暂时设计为五个表



参考:
疑惑
据我了解 要实现rbac模型 至少需要五个表 user表 role表 权限表 以及两个关联表 再拓展些可以引入用户组 权限功能 操作表等等 这就意味着我需要对原本项目进行分库分表的操作 需要对项目结构进行大改 我在思考一个问题 光是对于权限管理 现在仅对一个user模块就分出来五个表 之后要做大数据分析 人物画像 势必又需要存储更多关于user的字段 可能又要拓展出几个表出来 一个简单的用户模块可能到最后有十多个表 还是一次加一点一次加一点形成的 这不就意味着一直需要重构相关代码吗 真的合理吗
您的担忧非常合理!系统设计尤其是在权限管理和用户模块扩展上,一旦需求逐步变复杂,确实可能导致频繁的重构和数据表的拆分,这种现象在大部分项目中都会出现。以下从 数据库设计的扩展性 和 代码的可维护性 两方面来分析并提供一些建议,帮助您应对这种情况。
问题分析
1. 表设计的复杂化
权限管理本身需要多个表(如 user、role、permission`等),权限之间的关联表(如 user_role、role_permission)是实现灵活性的核心,但不可避免增加复杂性。 当系统从简单到复杂发展时,可能需要添加用户组、功能模块关联、操作记录等,导致数据表数量爆增。 例如,为了适应个性化需求,或为统计分析可能引入:
- 行为日志表(如
user\_behavior\_log) - 用户画像表(如
user\_profile) - 用户偏好表(如
user\_preferences)
从一个“小而精”的模块逐步演化为几十张表,是常见现象。 但这并不意味着数据库设计的问题,而是缺少对扩展性的提前规划。
2. 表结构变化带来的重构成本
数据库表的增加直接导致程序逻辑复杂度上升,无论是 SQL 查询、关联关系的维护,还是功能调用,都可能需要较多代码变更。 当没有清晰的分层和抽象,代码层面对表结构高度耦合,表改动会引起连锁重构,工作量激增。
针对性建议
要解决这个问题,可以从以下几方面入手:
1. 常见设计优化方案
(1)尽量减少核心表的直接改动
将用户模块(user表)和权限模块(role、permission表)分离,这是典型的 领域分离设计。 也就是说,权限模块应专注于权限逻辑,而用户模块专注用户属性数据。
(2)引入扩展字段机制
对于用户模块中的个人画像、大数据分析相关信息,尽量引入扩展表,而不是直接修改核心表。 常见的做法有两种:
JSON字段(动态扩展)
- 使用类似 extra_attributes 的 JSON 字段,存储不固定或非核心的数据,避免频繁修改表结构。
- 适用场景:适用于用户扩展配置不严格依赖关系型查询的场合(如用户兴趣标签
tags)。 - 缺点:在查询上有一定限制(如部分关系型操作不便)。
示例结构:
CREATE TABLE user (
id BIGINT PRIMARY KEY,
username VARCHAR(50),
...
extra_attributes JSON
);
垂直拆分表
创建专门的表存储扩展属性,用户对应多个扩展属性键值对记录,可以方便的横向扩展。
CREATE TABLE user_profile (
user_id BIGINT,
attribute_key VARCHAR(50),
attribute_value TEXT,
PRIMARY KEY (user_id, attribute_key)
);
(3)提前规划分库分表
您提到了“分库分表”,这是一个相当重要的扩展思路,当数据量变大时,建议:
- 按领域分库:将用户模块、权限模块拆分不同数据库,减少表之间的逻辑耦合,拆分后的库还可以独立扩展。
- 按业务分表:以
sharding的方式横向拆分大表,如按用户ID哈希、按时间分表等。
2. 代码架构层的解耦
将数据库表的变化对业务代码的影响降到最低,需要对代码设计进行解耦。 以下方法可以有效减少重构:
(1)统一的权限管理服务
将权限管理相关逻辑模块化,可以通过 单独的 RBAC Service 进行封装:
- 权限服务专注于用户、角色、权限的查询和判断,提供接口给系统其他部分使用。
- 避免因权限模块表结构改动影响用户模块的核心代码。
@Service
public class RbacService {
public boolean hasPermission(Long userId, String permissionCode) {
// 基于 user、role、permission 表进行逻辑判断
return ...;
}
}
(2)通过接口而非直接访问表
在业务逻辑中,尽量使用接口或服务访问用户相关信息,而不是直接操作数据库表。 例如:
- 在 DAO 层提供统一的用户数据访问接口,便于表结构变化时仅修改 DAO 层代码。
- 在权限相关判断中通过
API方式访问权限逻辑。
public interface UserService {
User findUserById(Long userId);
void updateUser(User user);
}
(3)领域模型设计
在复杂系统中引入领域驱动设计(DDD)的思想,进一步解耦业务逻辑和数据表的绑定:
- 核心业务(如用户画像计算)交由不同的领域服务处理,使用聚合根模式保护数据一致性。
- 非核心数据可以通过外部服务查询。
进一步探索
如果是一个正在成长的系统,可以分阶段逐步优化,以下是一种参考实施方案:
- 初期(小型单体系统)
- 将用户表、权限相关表等集中在一个数据库内,通过简单外键或关联关系实现。
- 利用 RBAC 和 JSON 等技术,满足短期灵活性需求。
- 中期(用户规模扩大,功能变复杂)
- 开始分库分表,例如将用户基本信息和行为日志拆分为不同的库。
- 引入服务化,解耦权限管理和用户管理模块。
- 后期(大规模分布式系统)
- 完整实现服务化,用户、权限模块独立部署。
- 从 RBAC 逐步向 PBAC、ABAC 迁移,根据需求不断优化权限模型。
总结
- 用户模块和权限模块的表设计复杂性是不可避免的,但可以通过提前规划、引入扩展字段及分库分表减少后期重构。
- 代码架构上,通过服务化和领域设计降低表结构变化对代码的影响,是减少重构和提升维度的关键。
- 数据库可以采用 JSON 字段和动态扩展表的方式来管理非核心信息,以减少频繁变更核心表的压力。
代码实现
项目分区导航:⬅️ 04-SecurityUtils 使用示例 | 05-权限控制模型 | ➡️ 06-RBAC模型最佳实践实现
💬 评论