土法炼钢兴趣小组的算法知识备份

【系统架构设计】授权架构:RBAC、ABAC 与策略引擎

文章导航

分类入口
architecture
标签入口
#authorization#RBAC#ABAC#ReBAC#Zanzibar#OPA

目录

上一篇:认证架构 下一篇:零信任架构

一个 SaaS 平台在初期用三个角色(Admin、Editor、Viewer)就能覆盖全部权限需求。当租户数量增长到数百家,每家又要求”只能看自己部门的数据”“审批流只对特定项目生效”时,角色数量从 3 个膨胀到 3000 个——这就是角色爆炸(Role Explosion)。本文围绕”当 RBAC(Role-Based Access Control)的角色爆炸时怎么办”这一核心问题,逐步展开 ABAC(Attribute-Based Access Control)、ReBAC(Relationship-Based Access Control)与策略引擎(Policy Engine)的架构设计。

一、问题场景

授权(Authorization)回答的是”已认证的主体能否对资源执行某操作”。与认证(Authentication)不同,授权的复杂度随业务增长呈指数级上升。

1.1 典型业务需求

在企业级系统中,授权需求通常包含以下维度:

1.2 授权决策的四个参与方

XACML(eXtensible Access Control Markup Language)标准定义了授权决策的四个核心组件:

组件 全称 职责
PEP 策略执行点(Policy Enforcement Point) 拦截请求,向 PDP 发起授权查询,执行决策结果
PDP 策略决策点(Policy Decision Point) 评估策略,返回允许/拒绝/不确定
PIP 策略信息点(Policy Information Point) 提供决策所需的属性数据(用户属性、资源属性、环境属性)
PAP 策略管理点(Policy Administration Point) 管理和存储策略规则
请求 --> [PEP] --查询--> [PDP] --获取属性--> [PIP]
                          |
                     [PAP: 策略存储]

这一架构模型贯穿后续所有授权方案的讨论。

1.3 从单体到微服务的授权挑战

在单体架构中,授权逻辑通常内嵌在业务代码里,通过 if-else 或注解完成。微服务架构下,挑战显著增加:

二、RBAC 模型与角色爆炸

2.1 RBAC 核心概念

RBAC 由 NIST(National Institute of Standards and Technology)标准化,其核心思想是通过角色(Role)间接地将权限(Permission)赋予用户(User)。

用户 --分配--> 角色 --关联--> 权限

NIST RBAC 模型定义了四个层级:

2.2 数据模型

-- RBAC 核心表结构
CREATE TABLE users (
    id         BIGINT PRIMARY KEY,
    username   VARCHAR(64) NOT NULL UNIQUE
);

CREATE TABLE roles (
    id         BIGINT PRIMARY KEY,
    name       VARCHAR(64) NOT NULL UNIQUE,
    parent_id  BIGINT REFERENCES roles(id)  -- 角色继承
);

CREATE TABLE permissions (
    id         BIGINT PRIMARY KEY,
    resource   VARCHAR(128) NOT NULL,
    action     VARCHAR(32)  NOT NULL,
    UNIQUE(resource, action)
);

CREATE TABLE user_roles (
    user_id    BIGINT REFERENCES users(id),
    role_id    BIGINT REFERENCES roles(id),
    PRIMARY KEY(user_id, role_id)
);

CREATE TABLE role_permissions (
    role_id       BIGINT REFERENCES roles(id),
    permission_id BIGINT REFERENCES permissions(id),
    PRIMARY KEY(role_id, permission_id)
);

2.3 角色爆炸问题

假设一个系统有以下维度:

如果用纯 RBAC 表达”某用户在某部门的某项目中以某密级角色操作”,需要的角色数量为:

3 x 10 x 5 x 4 = 600 个角色

这还只是四个维度。实际业务中维度更多,角色数量轻松突破数千甚至数万。角色爆炸带来的问题:

2.4 RBAC 的适用边界

RBAC 并非无用,它在以下场景仍然是最佳选择:

超出这些边界,就需要引入 ABAC 或 ReBAC。

三、ABAC 模型

3.1 核心思想

ABAC(Attribute-Based Access Control)不再依赖预定义的角色,而是基于属性(Attribute)动态计算授权决策。一条 ABAC 策略的形式为:

当 主体属性 AND 资源属性 AND 操作属性 AND 环境属性 满足条件时,允许/拒绝

3.2 属性分类

属性类别 示例
主体属性(Subject) 部门、职级、安全等级、所属团队
资源属性(Resource) 数据分类、所属项目、创建者、密级标签
操作属性(Action) 读取、写入、删除、导出、审批
环境属性(Environment) 当前时间、客户端 IP、设备类型、网络区域

3.3 XACML 架构

ABAC 的标准实现遵循 XACML 架构,各组件的交互流程如下:

sequenceDiagram
    participant Client as 客户端
    participant PEP as PEP(执行点)
    participant PDP as PDP(决策点)
    participant PIP as PIP(信息点)
    participant PAP as PAP(管理点)

    Client->>PEP: 发起资源请求
    PEP->>PDP: 授权查询(主体、资源、操作)
    PDP->>PIP: 获取主体属性
    PIP-->>PDP: 返回属性值
    PDP->>PIP: 获取资源属性
    PIP-->>PDP: 返回属性值
    PDP->>PAP: 加载匹配策略
    PAP-->>PDP: 返回策略集
    PDP->>PDP: 评估策略
    PDP-->>PEP: 返回决策(Permit/Deny)
    PEP-->>Client: 允许或拒绝请求

3.4 策略示例

以下是一条 ABAC 策略的伪代码表示:

策略:文档编辑权限
目标:resource.type == "document"
规则:
  IF subject.department == resource.ownerDepartment
     AND subject.clearance >= resource.classification
     AND action IN ["read", "write"]
     AND environment.time BETWEEN "09:00" AND "18:00"
  THEN Permit
  ELSE Deny

3.5 ABAC 的优势与局限

优势:

局限:

四、ReBAC 与 Google Zanzibar

4.1 ReBAC 核心思想

ReBAC(Relationship-Based Access Control)的核心观点是:权限由对象之间的关系(Relationship)决定。与 ABAC 关注属性不同,ReBAC 关注实体间的图结构关系。

例如:

4.2 Google Zanzibar 概述

Google 在 2019 年发表的论文《Zanzibar: Google’s Consistent, Global Authorization System》描述了其全球授权系统。Zanzibar 为 Google Drive、YouTube、Cloud IAM 等产品提供统一的授权服务,峰值每秒处理数百万次授权检查。

4.3 Relation Tuple 模型

Zanzibar 的核心数据结构是关系元组(Relation Tuple),格式为:

namespace:object#relation@user

具体示例:

doc:readme#owner@user:alice
doc:readme#viewer@group:engineering#member
folder:root#parent@doc:readme
group:engineering#member@user:bob

每个元组表达一条关系事实。其中各字段含义如下:

字段 含义 示例
namespace 对象类型的命名空间 doc、folder、group
object 具体对象的标识符 readme、root、engineering
relation 关系类型 owner、viewer、member、parent
user 关系的另一端,可以是具体用户或另一个对象集合 user:alice、group:engineering#member

4.4 命名空间配置

命名空间配置(Namespace Configuration)定义关系的继承和推导规则:

name: doc
relations:
  owner:
    union:
      - this                          # 直接关系
  editor:
    union:
      - this
      - computedUserset:
          relation: owner             # owner 隐含 editor
  viewer:
    union:
      - this
      - computedUserset:
          relation: editor            # editor 隐含 viewer
      - tupleToUserset:
          tupleset:
            relation: parent          # 从父对象继承
          computedUserset:
            relation: viewer

4.5 Check API 流程

Zanzibar 的核心 API 是 Check,用于回答”用户 U 是否对对象 O 具有关系 R”。

flowchart TD
    A[Check 请求: user:bob 是否为 doc:readme#viewer] --> B{直接关系查找}
    B -->|存在| C[返回 Permit]
    B -->|不存在| D{关系继承: viewer 包含 editor?}
    D -->|是| E{查找 doc:readme#editor@user:bob}
    E -->|存在| C
    E -->|不存在| F{关系继承: editor 包含 owner?}
    F -->|是| G{查找 doc:readme#owner@user:bob}
    G -->|存在| C
    G -->|不存在| H{间接关系: tupleToUserset}
    H --> I{查找 doc:readme#parent 的所有对象}
    I --> J[对每个父对象递归检查 viewer 关系]
    J -->|任一返回 Permit| C
    J -->|全部返回 Deny| K{用户组展开}
    K --> L{查找 doc:readme#viewer@group:*#member}
    L --> M[对每个组检查 user:bob 是否为 member]
    M -->|任一匹配| C
    M -->|全部不匹配| N[返回 Deny]

4.6 一致性模型

Zanzibar 使用 Zookie(也称 Snapshot Token)来解决分布式环境下的一致性问题。

问题场景:管理员刚刚撤销了 Alice 对 Document-123 的访问权限,但由于副本延迟,某个节点仍然返回”允许”。

解决方案:

  1. 每次写入关系元组时,系统返回一个 Zookie(本质上是一个时间戳或版本号);
  2. 后续的 Check 请求携带 Zookie;
  3. PDP 节点确保使用不早于 Zookie 所对应时间点的数据快照进行评估。
写入:DELETE doc:readme#viewer@user:alice
返回:zookie = "Zr4x8kP2"

检查:Check(doc:readme#viewer, user:alice, zookie="Zr4x8kP2")
结果:Deny(使用 >= Zr4x8kP2 时间点的数据)

这种机制在 Google 内部被称为”New Enemy Problem”的解决方案——确保权限撤销不会因为读取旧副本而被绕过。

4.7 Expand 与 Read API

除了 Check,Zanzibar 还提供:

4.8 开源实现

Zanzibar 模型有多个开源实现:

项目 语言 特点
SpiceDB Go 功能最完整,支持 Watch API
Keto(Ory) Go 与 Ory 生态集成,轻量级
OpenFGA Go Auth0 开源,支持 DSL 建模
Permify Go 支持多租户,提供 Playground

五、策略引擎:OPA

5.1 OPA 概述

OPA(Open Policy Agent)是 CNCF(Cloud Native Computing Foundation)毕业项目,提供通用的策略引擎。OPA 将策略从代码中解耦,以声明式语言 Rego 编写策略,通过 REST API 或嵌入库的方式集成。

5.2 Rego 策略语言

Rego 是一种声明式查询语言,语法受 Datalog 启发。以下是一个 API 授权策略示例:

package authz

import rego.v1

default allow := false

# 管理员拥有所有权限
allow if {
    input.user.roles[_] == "admin"
}

# 用户只能访问自己部门的数据
allow if {
    input.action == "read"
    input.resource.department == input.user.department
}

# 文档所有者可以编辑
allow if {
    input.action == "write"
    input.resource.type == "document"
    input.resource.owner == input.user.id
}

# 工作时间内才允许导出操作
allow if {
    input.action == "export"
    input.user.roles[_] == "editor"
    time.clock(time.now_ns())[0] >= 9
    time.clock(time.now_ns())[0] < 18
}

5.3 OPA 集成架构

OPA 支持两种主要集成模式:

Sidecar 模式:OPA 作为独立进程(通常是 Sidecar 容器)运行,应用通过 HTTP/gRPC 调用。

Library 模式:OPA 以 Go 库的形式嵌入应用进程,无网络开销。

flowchart LR
    subgraph Sidecar模式
        A1[应用服务] -->|HTTP/gRPC| B1[OPA Sidecar]
        B1 -->|定期拉取| C1[Bundle Server]
        B1 -->|推送| D1[Decision Log]
    end

    subgraph Library模式
        A2[应用服务 + OPA SDK] -->|定期拉取| C2[Bundle Server]
        A2 -->|推送| D2[Decision Log]
    end

    subgraph 管理平面
        C1 --- E[策略仓库 Git]
        C2 --- E
        D1 --- F[日志分析平台]
        D2 --- F
    end

5.4 Go 语言集成示例

以下示例展示如何在 Go 服务中以 Library 模式集成 OPA:

package main

import (
    "context"
    "encoding/json"
    "fmt"
    "log"

    "github.com/open-policy-agent/opa/rego"
)

// AuthzInput 构造授权请求的输入结构
type AuthzInput struct {
    User     UserInfo     `json:"user"`
    Action   string       `json:"action"`
    Resource ResourceInfo `json:"resource"`
}

type UserInfo struct {
    ID         string   `json:"id"`
    Department string   `json:"department"`
    Roles      []string `json:"roles"`
}

type ResourceInfo struct {
    Type       string `json:"type"`
    Department string `json:"department"`
    Owner      string `json:"owner"`
}

func main() {
    ctx := context.Background()

    // 从文件或 Bundle 加载策略
    query, err := rego.New(
        rego.Query("data.authz.allow"),
        rego.Load([]string{"./policy"}, nil),
    ).PrepareForEval(ctx)
    if err != nil {
        log.Fatalf("策略编译失败: %v", err)
    }

    // 构造授权请求
    input := AuthzInput{
        User: UserInfo{
            ID:         "alice",
            Department: "engineering",
            Roles:      []string{"editor"},
        },
        Action: "read",
        Resource: ResourceInfo{
            Type:       "document",
            Department: "engineering",
            Owner:      "bob",
        },
    }

    // 执行策略评估
    results, err := query.Eval(ctx, rego.EvalInput(input))
    if err != nil {
        log.Fatalf("策略评估失败: %v", err)
    }

    allowed := false
    if len(results) > 0 {
        allowed = results[0].Expressions[0].Value.(bool)
    }

    inputJSON, _ := json.MarshalIndent(input, "", "  ")
    fmt.Printf("输入:\n%s\n决策: %v\n", string(inputJSON), allowed)
}

5.5 Sidecar 模式下的 HTTP 调用

当 OPA 以 Sidecar 运行时,应用通过 HTTP 调用获取决策:

package authz

import (
    "bytes"
    "encoding/json"
    "fmt"
    "io"
    "net/http"
    "time"
)

// OPAClient 封装对 OPA Sidecar 的 HTTP 调用
type OPAClient struct {
    baseURL    string
    httpClient *http.Client
}

func NewOPAClient(baseURL string) *OPAClient {
    return &OPAClient{
        baseURL: baseURL,
        httpClient: &http.Client{
            Timeout: 100 * time.Millisecond,
        },
    }
}

type OPARequest struct {
    Input interface{} `json:"input"`
}

type OPAResponse struct {
    Result bool `json:"result"`
}

func (c *OPAClient) Check(input interface{}) (bool, error) {
    reqBody, err := json.Marshal(OPARequest{Input: input})
    if err != nil {
        return false, fmt.Errorf("序列化请求失败: %w", err)
    }

    resp, err := c.httpClient.Post(
        c.baseURL+"/v1/data/authz/allow",
        "application/json",
        bytes.NewReader(reqBody),
    )
    if err != nil {
        return false, fmt.Errorf("调用 OPA 失败: %w", err)
    }
    defer resp.Body.Close()

    body, err := io.ReadAll(resp.Body)
    if err != nil {
        return false, fmt.Errorf("读取响应失败: %w", err)
    }

    var opaResp OPAResponse
    if err := json.Unmarshal(body, &opaResp); err != nil {
        return false, fmt.Errorf("解析响应失败: %w", err)
    }

    return opaResp.Result, nil
}

5.6 Bundle 管理

OPA 的策略和数据通过 Bundle 机制分发:

# OPA 配置文件
services:
  bundle-server:
    url: https://policy-server.internal
    credentials:
      bearer:
        token: "${BUNDLE_TOKEN}"

bundles:
  authz:
    service: bundle-server
    resource: bundles/authz
    polling:
      min_delay_seconds: 10
      max_delay_seconds: 30

decision_logs:
  service: bundle-server
  resource: /logs
  reporting:
    min_delay_seconds: 5
    max_delay_seconds: 10

Bundle 的生命周期管理流程:

  1. 策略开发者在 Git 仓库中编写和修改 Rego 策略;
  2. CI/CD 流水线对策略执行单元测试(opa test);
  3. 测试通过后,将策略打包为 Bundle 并推送到 Bundle Server;
  4. 各 OPA 实例定期拉取最新 Bundle;
  5. 所有决策日志(Decision Log)异步上报,用于审计和分析。

5.7 Decision Logging

OPA 的决策日志记录每一次授权决策的完整上下文,包括输入、策略版本、决策结果和耗时。这对于安全审计和策略调试至关重要。

{
  "labels": {
    "id": "opa-sidecar-order-service",
    "version": "0.45.0"
  },
  "decision_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
  "input": {
    "user": {"id": "alice", "roles": ["editor"]},
    "action": "write",
    "resource": {"type": "document", "owner": "alice"}
  },
  "result": true,
  "timestamp": "2026-04-13T10:30:00Z",
  "metrics": {
    "timer_rego_query_eval_ns": 125000
  }
}

六、权限数据存储与缓存

6.1 存储模型选择

不同授权模型对存储有不同的要求:

授权模型 数据结构 推荐存储
RBAC 用户-角色-权限关系表 关系型数据库(PostgreSQL、MySQL)
ABAC 属性键值对 + 策略文件 属性存储 + 策略仓库(Git)
ReBAC 关系元组(图结构) 图数据库或专用存储(SpiceDB、CockroachDB)

6.2 权限反规范化

在高频查询场景下,规范化的权限数据(多表 JOIN)性能不足。常见的反规范化(Denormalization)策略:

策略一:预计算权限集

将用户的有效权限集预先计算并存储,避免实时遍历角色继承树。

-- 物化视图:用户有效权限
CREATE MATERIALIZED VIEW user_effective_permissions AS
SELECT DISTINCT ur.user_id, p.resource, p.action
FROM user_roles ur
JOIN roles r ON ur.role_id = r.id
JOIN role_permissions rp ON rp.role_id = r.id
JOIN permissions p ON rp.permission_id = p.id
UNION
SELECT DISTINCT ur.user_id, p.resource, p.action
FROM user_roles ur
JOIN roles r ON ur.role_id = r.id
JOIN roles parent ON r.parent_id = parent.id
JOIN role_permissions rp ON rp.role_id = parent.id
JOIN permissions p ON rp.permission_id = p.id;

策略二:位图编码

将权限编码为位图(Bitmap),用位运算进行授权判断:

// 权限位图:每个权限对应一个位
const (
    PermRead   uint64 = 1 << iota // 0b0001
    PermWrite                      // 0b0010
    PermDelete                     // 0b0100
    PermAdmin                      // 0b1000
)

type UserPermission struct {
    UserID     string
    ResourceID string
    Bitmap     uint64
}

func (up *UserPermission) HasPermission(perm uint64) bool {
    return up.Bitmap&perm == perm
}

func (up *UserPermission) Grant(perm uint64) {
    up.Bitmap |= perm
}

func (up *UserPermission) Revoke(perm uint64) {
    up.Bitmap &^= perm
}

6.3 缓存策略

权限数据的缓存需要在性能和一致性之间取得平衡。

本地缓存:

// 基于 LRU 的本地权限缓存
type PermissionCache struct {
    cache    *lru.Cache
    ttl      time.Duration
}

type cacheEntry struct {
    allowed   bool
    expiresAt time.Time
}

func NewPermissionCache(size int, ttl time.Duration) *PermissionCache {
    c, _ := lru.New(size)
    return &PermissionCache{cache: c, ttl: ttl}
}

func (pc *PermissionCache) Get(key string) (bool, bool) {
    val, ok := pc.cache.Get(key)
    if !ok {
        return false, false
    }
    entry := val.(*cacheEntry)
    if time.Now().After(entry.expiresAt) {
        pc.cache.Remove(key)
        return false, false
    }
    return entry.allowed, true
}

func (pc *PermissionCache) Set(key string, allowed bool) {
    pc.cache.Add(key, &cacheEntry{
        allowed:   allowed,
        expiresAt: time.Now().Add(pc.ttl),
    })
}

6.4 缓存失效模式

失效模式 机制 延迟 复杂度
TTL 过期 固定时间后失效 最高可达 TTL 值 低
事件驱动失效 权限变更时发布事件,订阅方清除缓存 秒级 中
版本号比对 每次请求携带版本号,与服务端比对 极低 中
Zookie/Snapshot Token 写入时返回 Token,读取时携带(Zanzibar 模型) 零(因果一致) 高

事件驱动失效示例:

// 使用消息队列进行权限缓存失效
type PermissionInvalidator struct {
    cache      *PermissionCache
    subscriber messaging.Subscriber
}

func (pi *PermissionInvalidator) Start(ctx context.Context) error {
    return pi.subscriber.Subscribe(ctx, "permission.changed", func(msg *messaging.Message) error {
        var event PermissionChangeEvent
        if err := json.Unmarshal(msg.Data, &event); err != nil {
            return err
        }

        // 按变更范围清除缓存
        switch event.Scope {
        case "user":
            pi.cache.InvalidateByPrefix("user:" + event.UserID)
        case "role":
            // 角色变更影响所有持有该角色的用户,需要批量失效
            pi.cache.InvalidateByPrefix("role:" + event.RoleID)
        case "global":
            pi.cache.Flush()
        }

        return nil
    })
}

6.5 最终一致性权衡

权限系统的一致性要求因场景而异:

七、工程案例

7.1 案例背景:SaaS 协作平台的授权演进

某 B2B SaaS 协作平台(类似企业级文档协作工具)在三年内经历了授权架构的三次演进。

第一阶段:纯 RBAC(0-100 家客户)

初期产品功能简单,定义了三个全局角色:

Admin   -> 所有操作权限
Editor  -> 创建、编辑、查看文档
Viewer  -> 仅查看文档

此阶段运行良好,管理简单,开发成本低。

第二阶段:角色爆炸(100-500 家客户)

随着多租户和组织层级的引入,客户提出了差异化权限需求:

为满足这些需求,团队开始为每个租户创建定制角色:

TenantA_DeptManager_Engineering
TenantA_DeptManager_Sales
TenantB_ExternalCollaborator
TenantC_Approver_ProjectX
...

角色数量从 3 个增长到 1200 个。问题开始显现:

第三阶段:混合架构(500+ 家客户)

团队决定重构授权架构,采用 RBAC + ReBAC 的混合方案:

7.2 混合架构设计

flowchart TD
    A[API 请求] --> B[API Gateway / PEP]
    B --> C{功能权限检查}
    C -->|RBAC| D[角色服务]
    D -->|通过| E{数据权限检查}
    D -->|拒绝| Z[返回 403]
    E -->|ReBAC| F[SpiceDB]
    F -->|通过| G{策略检查}
    F -->|拒绝| Z
    G -->|ABAC| H[OPA]
    H -->|通过| I[转发至后端服务]
    H -->|拒绝| Z

7.3 SpiceDB 关系建模

definition user {}

definition organization {
    relation admin: user
    relation member: user
}

definition workspace {
    relation org: organization
    relation admin: user
    relation member: user

    permission manage = admin + org->admin
    permission access = member + manage
}

definition document {
    relation workspace: workspace
    relation owner: user
    relation editor: user
    relation viewer: user

    permission write = owner + editor + workspace->manage
    permission read = viewer + write + workspace->access
    permission delete = owner + workspace->manage
}

7.4 迁移过程中的关键决策

决策点 选择 理由
ReBAC 实现 SpiceDB 而非自研 自研关系图遍历引擎的工程成本过高
ABAC 引擎 OPA Library 模式 避免 Sidecar 的网络延迟(P99 需 < 5ms)
缓存策略 本地 LRU + 事件驱动失效 平衡延迟和一致性
迁移策略 双写 + 影子模式 新旧系统并行运行,对比结果一致后切换
权限撤销一致性 Zookie Token 防止 New Enemy Problem

7.5 迁移效果

指标 迁移前 迁移后
角色数量 1200+ 6(全局角色)
授权决策延迟(P99) 12ms 4ms
权限相关工单/月 45 8
新租户上线授权配置时间 2 天 15 分钟
权限变更生效延迟 手动刷新 < 3 秒

八、选型对比

8.1 三种模型对比

维度 RBAC ABAC ReBAC
核心抽象 角色 属性 + 策略 关系元组
授权粒度 功能级 任意粒度 对象级
策略表达力 低 高 中高
管理复杂度 低(角色少时) 高 中
扩展性 差(角色爆炸) 好 好
性能特征 简单查表,极快 属性收集有开销 图遍历,中等
审计友好性 好(角色路径清晰) 差(策略复杂) 好(关系可解释)
适用规模 小中型 中大型 中大型
上下文感知 不支持 原生支持 需与 ABAC 结合
标准化程度 NIST RBAC XACML/ALFA Zanzibar 论文
典型实现 数据库表 + 代码逻辑 OPA、Axiomatics SpiceDB、OpenFGA
适合场景 内部管理系统,角色维度少 合规驱动,上下文丰富 协作平台,资源共享

8.2 OPA 集成模式对比

维度 Sidecar 模式 Library 模式
部署方式 独立容器/进程 嵌入应用进程
语言依赖 无(HTTP/gRPC) 仅 Go(原生);其他语言通过 WASM
网络延迟 有(通常 < 1ms) 无
策略更新 独立更新,不影响应用 需随应用重启或热加载
资源隔离 独立资源配额 共享应用资源
运维复杂度 高(额外容器管理) 低
适合场景 多语言微服务 Go 服务,对延迟敏感

8.3 选型决策树

根据业务需求,可按以下路径选择授权模型:

Q1: 权限维度是否超过 3 个?
  否 -> RBAC
  是 -> Q2

Q2: 权限是否与对象间关系强相关(共享、协作、层级)?
  是 -> ReBAC(Zanzibar 模型)
  否 -> Q3

Q3: 是否需要基于上下文动态决策(时间、地点、设备)?
  是 -> ABAC(OPA / XACML)
  否 -> RBAC + 数据过滤

实际工程中,混合架构是常态:RBAC 管功能权限,ReBAC 管资源级权限,ABAC 处理横切策略。

九、总结

授权架构没有银弹。RBAC 简单直接但不耐扩展;ABAC 灵活强大但管理成本高;ReBAC 在协作和资源共享场景中表现出色。工程实践中的关键原则:

  1. 从 RBAC 起步:不要过早引入复杂模型,在角色爆炸成为实际痛点时再演进;
  2. 策略与代码分离:使用 OPA 等策略引擎将授权逻辑从业务代码中剥离;
  3. 选择合适的一致性级别:授予权限可容忍最终一致性,撤销权限需要强一致性;
  4. 可审计性优先:授权系统必须能回答”谁在什么时候基于什么规则访问了什么资源”;
  5. 混合架构是常态:不同层级的权限用不同模型处理,通过 PEP 统一编排。

当 RBAC 的角色爆炸时,答案不是”抛弃 RBAC”,而是在合适的层次引入 ReBAC 和 ABAC,让每种模型各司其职。

参考资料

  1. Sandhu, R., et al. “Role-Based Access Control Models.” IEEE Computer, 1996.
  2. NIST. “An Introduction to Role-Based Access Control.” NIST Special Publication, 2010.
  3. OASIS. “eXtensible Access Control Markup Language (XACML) Version 3.0.” 2013.
  4. Paans, R., et al. “Zanzibar: Google’s Consistent, Global Authorization System.” USENIX ATC, 2019.
  5. Open Policy Agent Documentation. https://www.openpolicyagent.org/docs/latest/
  6. SpiceDB Documentation. https://authzed.com/docs
  7. OpenFGA Documentation. https://openfga.dev/docs
  8. Bertocci, V. “Authorization in Microservices.” O’Reilly, 2023.
  9. CNCF. “Open Policy Agent: Policy-based control for cloud native environments.” https://www.cncf.io/projects/open-policy-agent/
  10. Ory Keto Documentation. https://www.ory.sh/docs/keto

上一篇:认证架构 下一篇:零信任架构

同主题继续阅读

把当前热点继续串成多页阅读,而不是停在单篇消费。

2026-06-13 · architecture / security

【身份与访问控制工程】IAM 全景:为什么这是高价值赛道

从 2020 年 SolarWinds 到 2024 年 Okta 支持系统泄露,身份基础设施的安全失败反复证明一件事:IAM 不是 IT 支撑系统,而是安全架构的承重墙。本文建立现代 IAM 的全景地图——从认证协议、令牌体系、权限模型到身份治理与平台选型,给出 5 个贯穿全系列的核心问题。

2026-06-17 · architecture / security

【身份与访问控制工程】RBAC、ABAC、ReBAC:权限模型怎么选

RBAC 简单但会角色爆炸,ABAC 灵活但策略管理失控时更可怕,ReBAC 表达力强但引入了图遍历的性能约束。三种模型不是'选一个升级另一个'的线性关系,而是在表达能力、管理成本和性能三者之间做工程权衡。本文从每种模型的本质数据结构出发,拆解选型框架。

2026-06-18 · architecture / security

【身份与访问控制工程】Zanzibar 风格权限系统:Google 的全球授权引擎

Google Zanzibar 论文在 2019 年发布后,引发了开源授权系统的一波重新设计:Auth0 FGA、SpiceDB、Permify、Ory Keto——全都基于 Zanzibar 的'关系图+命名空间配置'模型。但论文本身只讲了 What,没深入 Why。本文从 Zanzibar 的 relation tuple 模型、namespace config 的语义、consistency 模型(Zookie)和工程权衡出发,拆解为什么 Zanzibar 的设计决策是这样的,以及你自己实现时要面对什么。


By .