2. ABAC 属性模型设计:用户属性、资源属性、环境属性、上下文属性设计原则
属性,是 ABAC 的核心“语言”。
规则之所以能动态计算权限,靠的就是不同维度的属性组合。说白了,没想清楚属性怎么设计,ABAC 就是一锅粥。
我记得刚开始带团队做 ABAC 时,大家把能想到的属性全塞进去,结果策略引擎跑一次要查十几个数据源,性能直接崩了。后来我们总结了一套设计原则,今天跟你聊聊。
2.1 用户属性设计
用户属性描述“谁”要发起操作。常见的有:部门、职级、角色、区域、入职时间、安全等级等。
设计原则很简单:只采集规则会用到的字段。我在项目里见过有人把用户身高、爱好都存进了属性系统,除了增加数据同步负担,没任何用。
department、jobLevel、region 这种稳定字段。像 lastLoginTime 这种高频变化的字段,除非规则真的需要,否则别放进来——每次属性变更都会触发策略重算,代价很高。
举个例子。某文档系统要求“只有本部门的员工才能编辑本部门文档”。那规则写:
// 伪代码示例
PEP.evaluate({
user: { department: "Engineering" },
resource: { ownerDepartment: "Engineering" },
action: "edit",
effect: "allow"
});
这里 department 就是关键用户属性。如果你没有这个属性,就得写死部门列表,或者通过角色关联,那就退化到 RBAC 了。
2.2 资源属性设计
资源属性描述“对什么”操作。文件、API、数据库表、微服务端点,都有自己的属性。
我建议把资源属性分成两类:
| 类别 | 示例 | 设计要点 |
|---|---|---|
| 静态属性 | 资源类型、创建者、所属项目、安全分类 | 资源创建时写入,很少变化。适合用属性标签存储。 |
| 动态属性 | 当前状态(草稿/已发布)、最后修改时间、使用次数 | 实时计算或缓存,注意性能。别在每次策略评估时都查数据库。 |
资源属性最容易犯的错误是“过度设计”。比如一个文件有 50 个元数据字段,全塞进属性系统。你想想看,策略评估时真的需要检查所有字段吗?通常也就三五个核心字段参与决策。其余字段放业务数据库就好,别往 PIP(策略信息点)里堆。
2.3 环境属性设计
环境属性描述“在什么条件下”。这里的“环境”是独立于用户和资源的外部因素。
常见环境属性:
- 时间:当前时间、工作日/节假日、上班时间/非上班时间。
- 网络位置:内网/外网、VPN 接入、IP 段、地理位置。
- 设备特征:终端类型、操作系统版本、是否越狱。
- 威胁情报:IP 信誉分、是否属于已知攻击源。
环境属性的特点是“瞬间状态”。每次请求都不一样,而且不能由用户伪造。设计时要保证数据源的实时性和权威性。
我习惯把环境属性封装成独立的 环境上下文服务。PEP 在评估时直接调用这个服务获取当前环境快照,而不是每次都硬编码到规则里。这样环境变化时,只需改服务逻辑,不用改策略规则。
2.4 上下文属性设计
上下文属性是最容易被忽略、也最容易出彩的维度。它描述“这次请求的会话级特征”。
举个例子:用户同时发起两个请求,一个是“查询工资”,一个是“查看同事绩效”。系统需要判断这些请求是否在同一个会话里、是否是越权尝试。
上下文属性通常包括:
- 会话 ID:用于关联同一用户的多步操作。
- 请求来源:同一个页面、同一个流程步骤。
- 操作频率:过去 5 秒内同一用户发出多少次同类请求。
- 信任等级:多因素认证等级、设备信任分数。
我曾经在电商后台权限项目中,发现有个运营账号总是在凌晨批量导出用户手机号。用户属性(运营角色)和资源属性(用户表)都允许导出,但行为明显异常。后来我们在上下文属性里加入了 requestBatchSize 和 timeWindow,配置一条规则:“单次请求导出超过 100 条且时区在非工作时间,触发审批”。这就是上下文属性的价值——补上了其他三个维度看不到的“动作模式”。
2.5 四类属性的设计对照
| 维度 | 回答的问题 | 数据来源 | 变更频率 | 设计侧重 |
|---|---|---|---|---|
| 用户属性 | 谁 | HR 系统、IAM、组织架构 | 低(月/年) | 稳定、可枚举 |
| 资源属性 | 对什么 | 资源元数据、CMDB、业务系统 | 中(日/周) | 精简核心字段 |
| 环境属性 | 在什么条件下 | 网络设备、时间服务、威胁情报 | 高(秒/分) | 实时、权威 |
| 上下文属性 | 本次请求的特征 | 会话管理、请求拦截器、行为分析 | 极高(每次请求) | 会话级、细粒度 |
最后给你个设计清单,每次新增属性时拿这个过一遍:
- 这个属性会出现在哪条规则里?
- 没有它,规则能否正确决策?
- 获取这个属性的成本(延迟、存储、一致性)是否可控?
- 属性值是否会频繁变化?变化后是否需要刷新缓存?