4、ABAC模型实战:属性定义与策略引擎设计

ABAC,说白了就是“看人下菜碟”的精细化版本。它不像RBAC那样只盯着角色,而是综合判断谁、对什么、在什么环境下,最终决定能不能干那件事。

我记得刚接手一个跨国项目时,业务方要求“中国区经理在工作时间能看到销售报表,但海外分公司经理只能看本地数据”。用RBAC得建一堆角色,用ABAC呢?三条策略就搞定了。这就是属性的力量。

4.1 三类核心属性定义

ABAC的基石就是属性。我习惯把它们分成三组:主体、资源、环境。你想想看,任何权限判断都逃不出这三个维度。

4.1.1 主体属性(Subject Attributes)

主体就是“谁”。不只是用户ID,而是能描述用户特征的一切标签。

属性类别示例说明
身份标识userId, employeeId唯一标识,基础中的基础
组织属性部门、职级、汇报线我在项目中常用部门+职级做粗粒度过滤
地域属性办公城市、国家、时区数据合规场景必备,比如GDPR
信任等级认证强度、设备指纹分高风险操作要求高信任等级
临时标签是否新人、是否借调动态赋予,用完即弃

我的经验:主体属性别一开始就搞太细。我见过有人定义了50多个属性,结果策略写起来自己都晕。先抓核心的5-8个,跑通了再扩展。

4.1.2 资源属性(Resource Attributes)

资源就是“对什么”。文件、API、数据库记录,都得有标签。

// 资源属性定义示例(JSON Schema)
{
  "resourceType": "document",
  "attributes": {
    "classification": { "type": "string", "enum": ["公开", "内部", "机密", "绝密"] },
    "ownerDept": { "type": "string" },
    "createdAt": { "type": "string", "format": "date-time" },
    "region": { "type": "string" },
    "tags": { "type": "array", "items": { "type": "string" } }
  }
}

嗯,这里要注意:资源属性最好由数据所有者维护,而不是安全团队拍脑袋。我曾经遇到一个项目,安全团队给所有文档打了“机密”标签,结果策略全失效了——因为没人能访问任何文档。

4.1.3 环境属性(Environment Attributes)

环境就是“在什么情况下”。这是ABAC最灵活的地方,也是很多人容易忽略的。

  • 时间维度:工作时间、节假日、季度末
  • 位置维度:内网IP、办公区WiFi、VPN接入
  • 风险维度:当前登录失败次数、异常行为评分
  • 设备维度:是否公司设备、操作系统版本、是否越狱

避坑指南:我曾经把环境属性全部放在策略引擎里实时计算,结果每次请求都要查5个外部系统,接口响应时间从20ms飙到800ms。后来加了本地缓存+异步刷新,才压回来。环境属性尽量用本地可获取的数据。

4.2 策略引擎设计

策略引擎是ABAC的大脑。我习惯把它拆成四个模块:策略管理、策略解析、策略评估、决策缓存。

ABAC策略引擎架构 主体属性 资源属性 环境属性 策略解析器 加载 → 编译 → 索引 策略存储 DB / Git / 配置中心 策略评估引擎 匹配 → 组合 → 裁决 决策缓存 TTL失效 / 事件驱逐 Permit / Deny / NotApplicable 关键设计点 • 策略版本化 • 变更审批流 • 模拟评估沙箱

4.2.1 策略模型设计

我推荐用目标-规则-条件三层结构。别把策略写成if-else面条代码。

// 策略模型示例
{
  "policyId": "POLICY-001",
  "name": "中国区经理访问销售报表",
  "target": {
    "subject": { "department": "销售部", "level": "经理及以上" },
    "resource": { "type": "report", "classification": "内部" },
    "environment": { "region": "中国", "timeRange": ["09:00", "18:00"] }
  },
  "rules": [
    {
      "effect": "Permit",
      "condition": {
        "allOf": [
          { "subject.region": { "equals": "中国" } },
          { "resource.ownerDept": { "equals": "销售部" } }
        ]
      }
    }
  ]
}

核心原则:策略的目标(Target)做粗筛,条件(Condition)做细判。目标不匹配直接跳过,性能能提升一个数量级。

4.2.2 评估算法

策略评估不是简单的“找到一条就返回”。我习惯用组合决策算法:

  1. 策略匹配:根据目标过滤出候选策略集
  2. 优先级排序:按策略优先级、精确度排序
  3. 条件求值:逐一评估每条策略的条件表达式
  4. 决策合并:处理多条匹配策略的冲突(Permit优先 / Deny优先 / 首次匹配)

我曾经踩过的坑:默认用了“Permit优先”,结果安全审计发现一条宽松策略覆盖了所有Deny策略。后来改成“Deny优先+显式Permit”,才符合最小权限原则。默认策略一定要设为Deny。

4.3 动态权限计算实战

动态计算是ABAC的杀手锏。用户属性变了、资源标签改了、环境风险升高了,权限立刻跟着变。不需要改代码,不需要重新部署。

4.3.1 实时计算 vs 预计算

模式适用场景延迟一致性我推荐
实时计算高频变更、风险敏感高(5-50ms)强一致API鉴权、支付操作
预计算+缓存低频变更、批量授权低(<1ms)最终一致菜单展示、报表列表
混合模式大部分场景可控可调我目前都在用

4.3.2 性能优化技巧

动态计算最怕的就是慢。我分享几个实战经验:

  • 属性预取:在策略评估前,批量加载所有需要的属性,避免N+1查询
  • 表达式编译:策略加载时就把条件表达式编译成可执行代码,别每次都解析JSON
  • 短路评估:遇到Deny直接返回,不再评估后续策略
  • 决策缓存:对相同的(主体,资源,环境)三元组缓存结果,设置合理的TTL
// 决策缓存伪代码
public class DecisionCache {
    private Cache<DecisionKey, DecisionResult> cache;
    
    public DecisionResult evaluate(RequestContext ctx) {
        DecisionKey key = buildKey(ctx);
        DecisionResult cached = cache.get(key);
        if (cached != null && !cached.isExpired()) {
            return cached;  // 缓存命中
        }
        
        DecisionResult result = policyEngine.evaluate(ctx);
        cache.put(key, result, Duration.ofSeconds(30));  // 30秒TTL
        return result;
    }
}

我的习惯:缓存TTL别设太长。我一般设30-60秒,既扛住峰值流量,又保证属性变更后能快速生效。对于风险敏感操作(比如转账),直接走实时计算,不走缓存。

4.3.3 动态属性注入

有些属性不是静态存储的,而是实时计算出来的。比如“用户当前风险评分”。

// 动态属性提供者接口
public interface DynamicAttributeProvider {
    String getAttributeName();
    Object resolve(Subject subject, Resource resource, Environment env);
}

// 示例:计算用户风险评分
public class RiskScoreProvider implements DynamicAttributeProvider {
    @Override
    public String getAttributeName() { return "riskScore"; }
    
    @Override
    public Object resolve(Subject subject, Resource resource, Environment env) {
        int failedLogins = env.get("recentFailedLogins");
        boolean fromNewDevice = !subject.getDevices().contains(env.get("deviceId"));
        // 简单评分逻辑
        return (failedLogins > 3 ? 30 : 0) + (fromNewDevice ? 20 : 0);
    }
}

嗯,这里要注意:动态属性提供者一定要有超时保护。我见过一个风险评分接口挂了,导致所有权限判断都卡住。加个50ms超时,超时了就返回默认值。

4.4 本章小结

ABAC的核心就三件事:定义好属性、设计好策略引擎、实现动态计算。属性是数据基础,策略引擎是逻辑核心,动态计算是价值体现。

我个人建议,刚开始别追求完美。先定义10个以内的核心属性,写5条关键策略,跑通一个业务场景。等团队熟悉了,再逐步扩展。毕竟,能落地的架构才是好架构。