三类决策
RBAC 把权限授予角色,再把角色分配给用户。ABAC 依据主体、资源、动作和环境的属性评估策略。ReBAC 判断图中主体与资源之间是否存在路径,这也是按对象共享的实现方式。
各模型如何工作
RBAC 是连接表:用户到角色、角色到权限。它易审计、评估快,但 editor 角色无法表达“文档 42 的编辑者”,除非为每个文档建角色。ABAC 用规则替代静态授权,例如 subject.department == resource.department && time.hour < 18,由策略决策点评估。ReBAC 存储 doc:42#viewer@group:eng#member 这样的元组并解析传递成员关系,Google 的 Zanzibar 是典型设计。
实践中,策略决策点负责评估,API 中的策略执行点负责落实。绝不要信任客户端传来的角色,必须从已认证身份推导。
何时使用
RBAC 适合粗粒度的岗位权限和管理后台;ABAC 适合区域、密级、时间或数据分类等上下文;ReBAC 适合带共享、文件夹和嵌套团队的协作产品。多数系统三者并用:角色授予“可以共享”的能力,关系授予对某个文件夹的访问。
示例与常见误解
文档工具把 member 作为角色,但共享单篇文档使用元组而不是新建角色;ABAC 规则再限制承包商在非工作时段访问。
常见误解是某一种模型会胜出。真正的选择是哪种模型负责哪类决策,以及如何一致地执行。相关概念:最小权限、行级安全、租户隔离。
代码示例
import express from 'express';
import jwt from 'jsonwebtoken';
function requireAuthMiddleware(req, res, next) {
const header = req.headers.authorization ?? '';
const token = header.startsWith('Bearer ') ? header.slice(7) : null;
if (!token) return res.status(401).json({ error: 'token required' });
try {
req.claims = jwt.verify(token, process.env.JWT_SECRET);
next();
} catch {
res.status(403).json({ error: 'invalid token' });
}
}
function requireRoleMiddleware(...allowed) {
return (req, res, next) => {
const role = req.claims?.role;
if (!role || !allowed.includes(role)) {
return res.status(403).json({ error: 'role ' + role + ' not permitted' });
}
next();
};
}
const app = express();
app.delete('/invoices/:id',
requireAuthMiddleware,
requireRoleMiddleware('admin', 'finance'),
(req, res) => res.json({ deleted: req.params.id }),
);
app.get('/profile',
requireAuthMiddleware,
(req, res) => res.json({ userId: req.claims.sub }),
);
app.listen(3000);
package main
import (
"crypto/sha256"
"crypto/subtle"
"fmt"
)
func ConstantTimeEqual(a, b string) bool {
left := sha256.Sum256([]byte(a))
right := sha256.Sum256([]byte(b))
return subtle.ConstantTimeCompare(left[:], right[:]) == 1
}
func main() {
secret := "s3cr3t-token"
fmt.Println(ConstantTimeEqual(secret, "s3cr3t-token"))
fmt.Println(ConstantTimeEqual(secret, "s3cr3t-tokeX"))
fmt.Println(ConstantTimeEqual(secret, "short"))
}