3. 授权与访问控制:RBAC模型、ABAC模型、ACL列表、分布式环境下的权限管理

授权与访问控制,说白了就是解决「谁可以干什么」的问题。我做了十几年分布式系统,见过太多因为权限设计不合理导致的线上事故。有的公司直接把数据库密码写在配置文件里,有的把超级管理员权限分给实习生——嗯,这些坑我都踩过。

今天咱们聊聊四种主流的授权模型:RBAC、ABAC、ACL,以及分布式环境下的权限管理。我会结合自己的实战经验,把每个模型的优缺点、适用场景讲清楚。

3.1 RBAC模型:基于角色的访问控制

RBAC(Role-Based Access Control)是目前最常用的模型。它的核心思想很简单:用户不直接拥有权限,而是通过角色来获得权限

举个例子:你公司里有「管理员」、「编辑」、「访客」三种角色。管理员可以删除文章,编辑可以修改文章,访客只能看。你只需要给用户分配一个角色,权限就自动继承了。

核心三要素:

  • 用户(User):系统的操作者
  • 角色(Role):权限的集合
  • 权限(Permission):对资源的操作许可

我在项目中遇到过一个问题:一个电商平台有 200 多种权限,如果直接给每个用户分配权限,管理成本会爆炸。用 RBAC 之后,我们只定义了 5 个角色(超级管理员、运营、客服、商家、买家),用户量从 10 万涨到 500 万,权限管理依然清晰。

RBAC 的代码实现也很直观:

// 用户-角色-权限 关系表
CREATE TABLE users (
    id INT PRIMARY KEY,
    name VARCHAR(50)
);

CREATE TABLE roles (
    id INT PRIMARY KEY,
    name VARCHAR(50)  -- 'admin', 'editor', 'viewer'
);

CREATE TABLE permissions (
    id INT PRIMARY KEY,
    name VARCHAR(100) -- 'delete_article', 'edit_article'
);

-- 用户与角色关联
CREATE TABLE user_roles (
    user_id INT,
    role_id INT
);

-- 角色与权限关联
CREATE TABLE role_permissions (
    role_id INT,
    permission_id INT
);

避坑指南:我曾经在一个项目中把角色层级搞得太深(比如「超级管理员-管理员-子管理员-组长-组员」),结果权限继承逻辑变得极其复杂。我的建议是:角色层级不要超过 3 层,否则维护成本会指数级上升。

3.2 ABAC模型:基于属性的访问控制

RBAC 虽然好用,但有个硬伤:它只能根据「角色」做判断。如果你需要根据时间、地点、设备、用户属性等条件来控制权限,RBAC 就力不从心了。

这时候 ABAC(Attribute-Based Access Control)就派上用场了。它的核心是:根据用户、资源、环境的多维属性动态计算权限

举个例子:

  • 「允许 财务部门的员工工作时间(9:00-18:00) 查看 本部门的财务报表
  • 「禁止 任何用户境外 IP 访问 敏感数据

这些规则用 RBAC 很难表达,但 ABAC 可以轻松搞定。它的判断逻辑通常用策略引擎来实现:

// ABAC 策略示例(伪代码)
policy "access_finance_report" {
    effect = "allow"
    condition {
        user.department == "finance"
        AND resource.type == "report"
        AND resource.department == user.department
        AND environment.time >= "09:00"
        AND environment.time <= "18:00"
    }
}

我建议你在以下场景优先考虑 ABAC:

  • 权限规则经常变化(比如 SaaS 产品的多租户场景)
  • 需要细粒度控制(比如「只允许查看自己创建的数据」)
  • 合规要求严格(比如 GDPR 要求基于数据分类的访问控制)

注意:ABAC 的性能开销比 RBAC 大得多。每次请求都要计算属性、匹配策略,如果策略数量超过 1000 条,响应时间可能会从 1ms 飙升到 50ms。我曾经帮一个客户优化过,最后用缓存 + 预编译策略的方式把延迟降到了 5ms 以内。

3.3 ACL列表:访问控制列表

ACL(Access Control List)是最原始的授权模型。它直接记录「谁可以做什么」,没有角色、没有属性,就是一张大表。

举个例子:

用户 资源 权限
张三 文件A 读、写
李四 文件A
王五 文件B 读、写、删除

ACL 的优点就是简单、直观。Linux 文件系统用的就是 ACL——每个文件都有 owner、group、others 的读写执行权限。

但它的缺点也很明显:当用户和资源数量增长时,ACL 表会爆炸。你想想看,1000 个用户 × 10000 个文件,那就是 1000 万条记录。维护起来简直是噩梦。

我个人习惯只在以下场景用 ACL:

  • 资源数量很少(比如系统配置文件)
  • 权限规则极其简单(比如只区分读写)
  • 作为 RBAC/ABAC 的补充(比如用户对自己创建的文档有额外权限)

3.4 分布式环境下的权限管理

前面讲的都是单机或单体架构下的模型。到了分布式系统,事情就复杂多了。我遇到过几个典型问题:

3.4.1 权限数据的一致性

在分布式系统中,用户、角色、权限数据可能分散在多个服务里。比如用户服务管理用户,订单服务管理订单权限。如果权限数据不一致,就会出现「用户明明有权限,但某个服务却拒绝访问」的情况。

我的解决方案是:统一权限中心。把所有权限数据集中到一个服务里,其他服务通过 RPC 或 HTTP 调用查询权限。这样虽然增加了网络开销,但保证了数据一致性。

3.4.2 性能与缓存

每次请求都去权限中心查询,性能肯定扛不住。我建议做两级缓存:

  • 本地缓存:每个服务实例缓存用户的权限信息,TTL 设置为 5 分钟
  • 分布式缓存:用 Redis 做全局缓存,权限变更时主动失效

我曾经用这个方案支撑过每秒 10 万次的权限查询,平均延迟不到 2ms。

3.4.3 权限的传播与审计

在微服务架构中,一个请求可能经过 5-6 个服务。如果每个服务都独立鉴权,效率很低。我建议用 JWT(JSON Web Token) 来传递用户身份和权限信息:

// JWT 中携带的权限信息示例
{
  "sub": "user_12345",
  "roles": ["admin", "editor"],
  "permissions": ["read:order", "write:order"],
  "exp": 1700000000
}

每个服务只需要验证 JWT 的签名,然后从 token 中提取权限信息即可。这样既避免了重复查询,又实现了权限的链路传播。

避坑指南:我曾经犯过一个错误——把完整的权限列表塞进 JWT。结果 token 体积从 200 字节膨胀到 5KB,每次请求的网络开销都很大。后来我只在 JWT 里放角色 ID,权限信息通过本地缓存查询,token 体积降到了 300 字节。

3.4.4 动态权限变更

分布式环境下,权限变更后需要立即生效。但缓存有 TTL,JWT 有有效期,怎么解决?

我的做法是:

  1. 权限变更时,通过消息队列(如 Kafka)广播变更事件
  2. 各服务监听事件,主动失效本地缓存
  3. 对于 JWT,设置较短的过期时间(比如 15 分钟),配合刷新机制

这样既保证了实时性,又不会因为频繁刷新导致性能问题。

3.5 如何选择?

说了这么多,到底该用哪种模型?我根据经验总结了一张表:

场景 推荐模型 理由
企业内部管理系统 RBAC 角色固定,权限规则简单
SaaS 多租户平台 ABAC 租户间隔离,权限规则复杂
文件存储系统 ACL 资源粒度细,权限规则简单
大型分布式系统 RBAC + ABAC 混合 角色做粗粒度控制,属性做细粒度补充

最后说一句:没有银弹。我见过有人非要用 ABAC 实现一个只有 3 个角色的系统,结果把简单问题复杂化了。也见过有人用 ACL 管理 10 万用户的权限,最后运维崩溃。选模型之前,先想清楚你的业务场景和未来 2 年的增长预期。

嗯,授权与访问控制这块就聊到这儿。下一章咱们聊聊分布式系统中的身份认证与单点登录,那又是另一番天地了。