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

【系统架构设计百科】授权架构: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-04-13 · architecture

【系统架构设计百科】架构质量属性:不只是"高可用高性能"

需求评审时写下的'高可用、高性能、高并发',到了架构设计阶段几乎无法落地——因为它们不是可执行的需求。本文从 SEI/CMU 的质量属性理论出发,用 stimulus-response 场景模型把模糊需求变成可量化、可验证的架构约束,并拆解属性之间的冲突与联动关系。

2026-04-13 · architecture

【系统架构设计百科】告警策略:如何避免"狼来了"

大多数团队的告警系统都在制造噪声而不是传递信号。阈值告警看似直观,实则产生大量误报和漏报,值班工程师在凌晨三点被叫醒,却发现只是一次无害的毛刺。本文从告警疲劳的工业数据出发,拆解基于 SLO 的多窗口燃烧率告警算法,深入 Alertmanager 的路由、抑制与分组机制,结合 PagerDuty 的告警疲劳研究和真实工程案例,给出一套可落地的告警策略设计方法。

2026-04-13 · architecture

【系统架构设计百科】复杂性管理:架构的核心战场

系统复杂性是架构腐化的根源——本文从 Brooks 的本质复杂性与偶然复杂性划分出发,结合认知负荷理论与 Parnas 的信息隐藏原则,系统阐述复杂性的来源、度量与控制手段,并给出可操作的架构策略


By .