3. 权限验证基础:认证与授权的区别及常见权限模型
在构建微服务与 BFF(Backend For Frontend)架构时,权限验证是保障系统安全的第一道防线。很多初学者容易混淆“认证”与“授权”这两个核心概念,导致在架构设计阶段就埋下安全隐患。本章将从基础概念出发,厘清认证与授权的本质区别,并深入剖析三种主流权限模型:RBAC、ABAC 与 PBAC,为后续 GoBFF 实战中的边界验证打下坚实的理论基础。
3.1 认证(Authentication)与授权(Authorization)的区别
认证与授权虽然经常被一起提及,但它们在安全体系中承担着完全不同的职责。简单来说:认证解决“你是谁”的问题,授权解决“你能做什么”的问题。
| 维度 | 认证(Authentication) | 授权(Authorization) |
|---|---|---|
| 核心问题 | 你是谁? | 你能做什么? |
| 执行顺序 | 先执行,是授权的前提 | 后执行,依赖认证结果 |
| 传递信息 | 身份凭证(密码、Token、证书) | 权限策略、角色、属性 |
| 常见机制 | JWT、OAuth2、Session、Basic Auth | RBAC、ABAC、ACL、PBAC |
| 失败结果 | 401 Unauthorized(未认证) | 403 Forbidden(无权限) |
| 在 GoBFF 中的位置 | BFF 网关层或 API 网关 | BFF 业务逻辑层或下游微服务 |
下图展示了认证与授权在请求处理流程中的先后关系与职责边界:
3.2 常见权限模型概述
在微服务架构中,选择正确的权限模型直接影响系统的可维护性、灵活性和性能。目前业界最成熟的三种模型分别是:基于角色的访问控制(RBAC)、基于属性的访问控制(ABAC) 和 基于策略的访问控制(PBAC)。下表从多个维度对三者进行对比:
| 维度 | RBAC(基于角色) | ABAC(基于属性) | PBAC(基于策略) |
|---|---|---|---|
| 核心元素 | 用户、角色、权限 | 主体、资源、环境、操作 | 策略规则、条件、效果 |
| 粒度 | 粗粒度(角色级) | 细粒度(属性级) | 可粗可细(策略定义) |
| 灵活性 | 中等,角色变更需管理员操作 | 高,属性组合可动态生成权限 | 高,策略可热加载 |
| 复杂度 | 低,易于理解和实施 | 高,属性管理复杂 | 中高,策略引擎设计复杂 |
| 适用场景 | 企业后台、CMS、标准 CRUD | 金融、医疗、多租户系统 | 微服务网关、API 治理 |
| Go 生态支持 | casbin、kataras/role | casbin(支持 ABAC)、openfga | openfga、topaz、cerbos |
3.3 RBAC:基于角色的访问控制
RBAC 是最经典的权限模型,其核心思想是将权限分配给角色,再将角色分配给用户。用户通过角色间接获得权限,而不是直接与权限挂钩。这种解耦方式极大地简化了权限管理。
RBAC 的核心要素:
- 用户(User):系统的操作者,可以是一个人、一个服务账号或一个机器人。
- 角色(Role):权限的集合,例如“管理员”、“编辑者”、“查看者”。
- 权限(Permission):对某个资源执行某个操作的许可,例如“创建订单”、“删除用户”。
- 会话(Session):用户激活的角色集合,一个用户可以在一次会话中激活多个角色。
下面是一个典型的 RBAC 数据模型示例(Go 结构体定义):
// RBAC 核心模型
type User struct {
ID string `json:"id"`
Username string `json:"username"`
Roles []string `json:"roles"` // 用户关联的角色ID列表
}
type Role struct {
ID string `json:"id"`
Name string `json:"name"`
Permissions []string `json:"permissions"` // 角色拥有的权限标识列表
}
// 权限检查函数
func HasPermission(user *User, requiredPermission string) bool {
// 实际项目中应从缓存或数据库加载角色-权限映射
rolePermissions := map[string][]string{
"admin": {"read", "write", "delete"},
"editor": {"read", "write"},
"viewer": {"read"},
}
for _, roleID := range user.Roles {
if perms, ok := rolePermissions[roleID]; ok {
for _, p := range perms {
if p == requiredPermission {
return true
}
}
}
}
return false
}
3.4 ABAC:基于属性的访问控制
ABAC 通过评估主体(用户)、资源、环境和操作的多维属性来决定是否允许访问。相比 RBAC 的“角色”单一维度,ABAC 可以表达更复杂的业务规则,例如:“只允许财务部门的经理在工作时间查看本部门的薪资报表”。
ABAC 的四类核心属性:
- 主体属性(Subject Attributes):用户ID、部门、职位、安全等级、地理位置。
- 资源属性(Resource Attributes):资源类型、所属部门、敏感级别、创建时间。
- 环境属性(Environment Attributes):当前时间、IP 地址、设备类型、网络环境。
- 操作属性(Action Attributes):操作类型(读/写/删除)、操作频率、操作方式。
以下是一个使用 Casbin 实现 ABAC 的 Go 代码示例:
// ABAC 请求结构体
type ABACRequest struct {
Subject string // 用户ID
Department string // 用户所属部门
Resource string // 资源ID
ResDept string // 资源所属部门
Action string // 操作
Time time.Time // 请求时间
}
// Casbin ABAC 匹配函数
func ABACMatchFunc(args ...interface{}) (interface{}, error) {
req := args[0].(ABACRequest)
rule := args[1].([]string)
// 规则格式: [subject, department, resource, resDept, action, timeRange]
// 例如: ["*", "finance", "*", "finance", "read", "09:00-18:00"]
// 检查部门匹配
if rule[1] != "*" && rule[1] != req.Department {
return false, nil
}
// 检查资源部门匹配
if rule[3] != "*" && rule[3] != req.ResDept {
return false, nil
}
// 检查时间范围
if rule[5] != "*" {
// 解析时间范围并比较
// ...
}
return true, nil
}
3.5 PBAC:基于策略的访问控制
PBAC 将权限决策抽象为独立的策略规则,通常使用声明式语言(如 Rego、CEL)或 YAML/JSON 配置文件来定义。PBAC 的核心优势在于策略与代码分离,权限变更无需修改业务代码,只需更新策略配置即可热生效。
PBAC 的典型架构组件:
- 策略决策点(PDP):负责评估策略并做出授权决策的引擎。
- 策略执行点(PEP):拦截请求并调用 PDP 获取决策结果,然后执行允许或拒绝。
- 策略管理点(PAP):提供策略的创建、更新、删除管理界面。
- 策略信息点(PIP):提供策略评估所需的属性数据源。
下图展示了 PBAC 在微服务架构中的组件交互关系:
PBAC 策略示例(使用 Rego 语言):
package authz
# 策略:允许用户删除自己创建的订单
default allow = false
allow {
input.action == "delete"
input.resource.type == "order"
input.subject.id == input.resource.owner_id
}
# 策略:允许管理员在任何时间删除任何订单
allow {
input.action == "delete"
input.resource.type == "order"
"admin" in input.subject.roles
}
# 策略:允许财务人员在09:00-18:00查看财务报表
allow {
input.action == "read"
input.resource.type == "financial_report"
"finance" in input.subject.departments
time_clock(input.time, "09:00", "18:00")
}
3.6 如何为 GoBFF 选择权限模型
在 GoBFF 架构中,权限模型的选择需要综合考虑 BFF 的定位、下游微服务的复杂度以及团队维护能力。以下是一份决策指南:
| 场景特征 | 推荐模型 | 理由 |
|---|---|---|
| BFF 仅做路由聚合,业务逻辑简单 | RBAC | 实现成本低,角色清晰,易于审计 |
| 多租户 SaaS,租户间数据隔离严格 | ABAC + 租户属性 | 通过租户ID属性实现天然隔离,无需为每个租户创建角色 |
| BFF 对接多个异构下游,权限规则频繁变更 | PBAC | 策略热加载,无需重启 BFF 服务即可调整权限 |
| 混合场景:部分粗粒度、部分细粒度 | RBAC + ABAC 混合 | 基础权限用 RBAC,特殊规则用 ABAC 补充 |