第十七章:授权架构模式
“好的授权架构应该像空气一样:无处不在,但用户感觉不到它的存在。”
mindmap
root((授权架构))
演进
硬编码
配置文件
策略引擎
外部化授权
XACML 架构
PEP
PDP
PIP
PAP
微服务模式
Gateway
Service Mesh
应用层
混合
多租户
租户隔离
权限继承
跨租户
17.1 授权架构的演进
Level 0: 硬编码
if user.role == "admin":
allow()
→ 问题:修改权限需要改代码、重新部署
Level 1: 配置文件
permissions = load_config("permissions.yaml")
→ 问题:缺乏测试、审计,配置散落各处
Level 2: 策略引擎
result = opa.evaluate(input)
→ 改进:策略与代码分离,可测试
Level 3: 外部化授权(Authorization as a Service)
result = authz_service.check(user, action, resource)
→ 最佳:统一授权服务,所有应用共享
17.2 XACML 授权架构
┌──────────┐ ┌──────────┐ ┌──────────┐
│ 用户 │───▶│ PEP │───▶│ 应用 │
│ │ │ 策略执行点 │ │ 资源 │
└──────────┘ └────┬─────┘ └──────────┘
│
│ 授权请求
▼
┌──────────┐
│ PDP │◀──── ┌──────────┐
│ 策略决策点 │ │ PAP │
│ (OPA/ │ │ 策略管理点 │
│ OpenFGA)│ │ (管理界面) │
└────┬─────┘ └──────────┘
│
│ 查询属性
▼
┌──────────┐
│ PIP │
│ 策略信息点 │
│ (用户属性 │
│ 资源属性) │
└──────────┘
组件 |
职责 |
实现 |
|---|---|---|
PEP |
拦截请求,执行决策 |
API Gateway、中间件、Sidecar |
PDP |
评估策略,做出决策 |
OPA、OpenFGA、Cedar |
PIP |
提供决策所需的属性数据 |
用户服务、LDAP、数据库 |
PAP |
管理策略的创建和更新 |
管理界面、Git |
17.3 微服务授权模式
模式 1:Gateway 集中授权
┌──────────┐ ┌──────────────┐ ┌──────────┐
│ 客户端 │───▶│ API Gateway │───▶│ 微服务 │
│ │ │ ┌─────────┐ │ │ 信任 GW │
│ │ │ │ 认证 │ │ │ 不做授权 │
│ │ │ │ 授权 ✅ │ │ │ │
│ │ │ │ 限流 │ │ │ │
│ │ │ └─────────┘ │ │ │
└──────────┘ └──────────────┘ └──────────┘
优点:简单、集中管理 缺点:粗粒度、Gateway 成为瓶颈
模式 2:Service Mesh 授权
┌──────────────────────────────────────┐
│ Kubernetes Pod │
│ ┌──────────┐ ┌────────────────┐ │
│ │ 微服务 │◀──▶│ Envoy Sidecar │ │
│ │ 业务逻辑 │ │ ┌──────────┐ │ │
│ │ │ │ │ mTLS │ │ │
│ │ │ │ │ AuthzPolicy│ │ │
│ │ │ │ └──────────┘ │ │
│ └──────────┘ └────────────────┘ │
└──────────────────────────────────────┘
模式 3:应用层授权
# 应用内授权 — 最细粒度
@app.put("/api/documents/{doc_id}")
async def update_document(
doc_id: str,
user: User = Depends(get_current_user),
):
# 调用外部授权服务
allowed = await openfga_client.check(
user=f"user:{user.id}",
relation="can_edit",
object=f"document:{doc_id}",
)
if not allowed:
raise HTTPException(403, "Cannot edit this document")
# 业务逻辑...
模式 4:混合模式(推荐)
┌──────────┐ ┌──────────────┐ ┌──────────────────┐
│ 客户端 │───▶│ API Gateway │───▶│ 微服务 │
│ │ │ 粗粒度授权 │ │ ┌──────────────┐ │
│ │ │ • 认证 │ │ │ 细粒度授权 │ │
│ │ │ • 角色检查 │ │ │ • 资源级权限 │ │
│ │ │ • 速率限制 │ │ │ • OpenFGA │ │
│ │ │ │ │ │ • OPA │ │
│ │ │ │ │ └──────────────┘ │
└──────────┘ └──────────────┘ └──────────────────┘
17.4 多租户授权设计
多租户授权模型(OpenFGA):
type user
type tenant
relations
define admin: [user]
define member: [user] or admin
type project
relations
define tenant: [tenant]
define admin: [user] or admin from tenant
define member: [user] or admin
define can_manage: admin
define can_access: member or can_manage
type resource
relations
define project: [project]
define owner: [user]
define editor: [user] or owner or can_manage from project
define viewer: [user] or editor or can_access from project
租户隔离策略
策略 |
描述 |
实现 |
|---|---|---|
数据隔离 |
每个租户的数据完全隔离 |
数据库 schema/表前缀 |
权限隔离 |
租户 A 的用户无法访问租户 B |
OpenFGA 关系检查 |
管理隔离 |
租户管理员只能管理自己的租户 |
租户级 admin 角色 |
跨租户访问 |
特殊场景下的跨租户协作 |
显式的跨租户关系元组 |
17.5 性能优化
缓存策略
import redis
import json
from functools import lru_cache
r = redis.Redis()
async def check_permission_cached(user_id: str, relation: str, object_id: str) -> bool:
"""带缓存的权限检查"""
cache_key = f"authz:{user_id}:{relation}:{object_id}"
# 1. 检查缓存
cached = r.get(cache_key)
if cached is not None:
return cached == b"1"
# 2. 调用 OpenFGA
result = await openfga_client.check(
user=f"user:{user_id}",
relation=relation,
object=object_id,
)
# 3. 写入缓存(TTL 60秒)
r.setex(cache_key, 60, "1" if result.allowed else "0")
return result.allowed
def invalidate_permission_cache(object_id: str):
"""权限变更时清除相关缓存"""
pattern = f"authz:*:*:{object_id}"
for key in r.scan_iter(pattern):
r.delete(key)
批量检查
async def batch_check_permissions(user_id: str, objects: list[str], relation: str) -> dict:
"""批量权限检查"""
results = {}
checks = [
openfga_client.check(
user=f"user:{user_id}",
relation=relation,
object=obj,
)
for obj in objects
]
responses = await asyncio.gather(*checks)
for obj, resp in zip(objects, responses):
results[obj] = resp.allowed
return results
17.6 实战:SaaS 平台授权架构
┌─────────────────────────────────────────────────────┐
│ SaaS 平台授权架构 │
│ │
│ ┌──────────┐ ┌──────────────┐ ┌───────────┐ │
│ │ Web/Mobile│───▶│ API Gateway │───▶│ 微服务集群 │ │
│ │ 客户端 │ │ (Kong/Envoy) │ │ │ │
│ └──────────┘ │ • JWT 验证 │ │ ┌───────┐ │ │
│ │ • 租户路由 │ │ │用户服务│ │ │
│ │ • 速率限制 │ │ └───┬───┘ │ │
│ └──────────────┘ │ │ │ │
│ │ ▼ │ │
│ ┌──────────────────────────────┐ │ ┌───────┐ │ │
│ │ 授权服务层 │ │ │项目服务│ │ │
│ │ ┌──────────┐ ┌───────────┐ │ │ └───┬───┘ │ │
│ │ │ OpenFGA │ │ OPA │ │ │ │ │ │
│ │ │ (ReBAC) │ │ (ABAC) │ │ │ ▼ │ │
│ │ │ 关系权限 │ │ 条件策略 │ │ │ ┌───────┐ │ │
│ │ └──────────┘ └───────────┘ │ │ │资源服务│ │ │
│ └──────────────────────────────┘ │ └───────┘ │ │
│ └───────────┘ │
└─────────────────────────────────────────────────────┘
17.7 小结
授权架构从硬编码演进到外部化授权即服务
XACML 架构(PEP/PDP/PIP/PAP)是授权系统的标准参考架构
混合模式最实用:Gateway 粗粒度 + 应用层细粒度
多租户授权需要数据隔离、权限隔离、管理隔离
缓存和批量检查是授权性能优化的关键手段
OpenFGA(ReBAC)+ OPA(ABAC)的组合覆盖大多数授权需求