4. 权限模型设计:RBAC、ABAC 模型对比与网关抽象
在权限审计网关中,权限模型是决定“谁(Who)能对什么(What)执行何种操作(How)”的核心逻辑。本章深入对比两种主流模型——RBAC(基于角色的访问控制)与ABAC(基于属性的访问控制),并阐述如何在网关层进行统一的抽象表示。
4.1 RBAC 模型:角色驱动的静态权限
RBAC 通过“用户 → 角色 → 权限”的映射关系实现访问控制。其核心思想是将权限授予角色,再将角色授予用户,从而简化权限管理。
| 要素 | 说明 | 网关中的抽象 |
|---|---|---|
| 用户(User) | 访问系统的实体(如 API 调用方) | JWT 中的 sub 或 user_id 声明 |
| 角色(Role) | 权限的集合(如 admin、editor、viewer) | JWT 中的 roles 声明(字符串数组) |
| 权限(Permission) | 对资源的操作许可(如 article:write) |
网关策略引擎中的规则键 |
| 会话(Session) | 用户与角色的动态绑定关系 | 请求上下文中的 ctx.Roles 字段 |
网关实践要点:RBAC 适用于权限层级固定、角色数量有限的场景。在网关层,通常将角色列表解析到请求上下文中,策略引擎通过预加载的“角色-权限”映射表进行快速匹配。
4.2 ABAC 模型:属性驱动的动态权限
ABAC 基于主体(Subject)、资源(Resource)、动作(Action)和环境(Environment)四类属性进行动态评估。其粒度更细,能够处理复杂的上下文敏感场景。
| 属性类别 | 示例 | 网关中的抽象 |
|---|---|---|
| 主体属性 | 用户 ID、部门、安全等级、地理位置 | JWT 声明 + 请求上下文扩展字段 |
| 资源属性 | 资源类型、所属项目、数据分类、创建时间 | 请求路径、请求头、资源元数据缓存 |
| 动作属性 | HTTP 方法(GET/POST/PUT/DELETE)、操作类型 | 请求方法 + 路由参数 |
| 环境属性 | 当前时间、IP 段、网络类型、客户端版本 | 请求来源 IP、时间戳、User-Agent |
性能考量:ABAC 每次请求都需要评估一组属性表达式,对网关性能有直接影响。建议使用预编译的策略表达式(如 CEL、Rego)并启用属性缓存,避免重复解析。
4.3 RBAC vs ABAC 核心对比
| 对比维度 | RBAC | ABAC |
|---|---|---|
| 权限粒度 | 粗粒度(角色级别) | 细粒度(属性级别) |
| 管理复杂度 | 低,角色数量可控 | 高,属性与策略数量易膨胀 |
| 动态性 | 静态,需管理员手动变更角色 | 动态,属性变化自动影响权限 |
| 适用场景 | 企业内部系统、CMS、后台管理 | 多租户 SaaS、金融风控、数据脱敏 |
| 网关实现成本 | 低,查表即可 | 高,需集成策略引擎 |
| 审计可追溯性 | 容易,角色变更记录清晰 | 较复杂,需记录属性快照 |
4.4 网关中的统一抽象表示
为了兼顾 RBAC 的简洁性与 ABAC 的灵活性,权限审计网关通常采用分层抽象架构:底层支持 RBAC 快速过滤,上层通过 ABAC 策略引擎进行精细化裁决。
4.5 Go 语言中的抽象实现
在网关代码中,我们通过接口抽象统一两种模型。以下是一个精简的权限评估器接口定义:
// PermissionEvaluator 权限评估器接口
type PermissionEvaluator interface {
// Evaluate 评估请求是否具有指定权限
// 返回 true 表示允许,false 表示拒绝
Evaluate(ctx context.Context, req *PermissionRequest) (bool, error)
}
// PermissionRequest 权限请求上下文
type PermissionRequest struct {
UserID string // 用户 ID
Roles []string // 用户角色列表(RBAC 使用)
Action string // 请求动作(如 "read", "write")
Resource string // 资源标识(如 "article:123")
Attributes map[string]interface{} // 扩展属性(ABAC 使用)
Env map[string]interface{} // 环境属性(ABAC 使用)
}
// RBACEvaluator RBAC 实现
type RBACEvaluator struct {
rolePerms map[string]map[string]bool // role -> action:resource -> allow
}
func (e *RBACEvaluator) Evaluate(ctx context.Context, req *PermissionRequest) (bool, error) {
key := req.Action + ":" + req.Resource
for _, role := range req.Roles {
if perms, ok := e.rolePerms[role]; ok {
if allowed, ok := perms[key]; ok {
return allowed, nil
}
}
}
return false, nil // 默认拒绝
}
// ABACEvaluator ABAC 实现(使用 CEL 引擎示例)
type ABACEvaluator struct {
policies []*Policy
}
func (e *ABACEvaluator) Evaluate(ctx context.Context, req *PermissionRequest) (bool, error) {
for _, p := range e.policies {
if p.Matches(req) {
return p.Effect == EffectAllow, nil
}
}
return false, nil
}
架构决策:在网关启动时,将 RBAC 映射表加载到内存中(如
sync.Map),ABAC 策略编译为可执行的 AST 缓存。请求到达时,先执行 RBAC 查表,若未命中则调用 ABAC 引擎。这种“先粗后细”的策略将 80% 的请求拦截在 RBAC 层,显著降低 ABAC 引擎的调用频率。
4.6 模型选择决策树
在实际网关设计中,可根据以下条件快速选择主导模型:
- 角色数量是否 < 50? → 是:优先 RBAC;否:考虑 ABAC
- 权限变更频率是否 > 每天 10 次? → 是:ABAC 更灵活;否:RBAC 更稳定
- 是否需要根据时间、IP 等环境因素控制访问? → 是:必须引入 ABAC;否:RBAC 足够
- 审计日志是否需要记录每次决策的详细属性? → 是:ABAC 天然支持;否:RBAC 可简化
- 团队是否有运维能力维护策略 DSL? → 是:可上 ABAC;否:建议 RBAC + 少量 ABAC 扩展
推荐实践:大多数权限审计网关采用“RBAC 主体 + ABAC 扩展”的混合模式。即:用 RBAC 管理 90% 的通用权限,对敏感操作(如删除、导出、跨部门访问)叠加 ABAC 属性规则。这样既保持了核心模型的简洁,又保留了应对复杂场景的弹性。