权限即数据:企业系统中的字段级访问控制架构实战(β=0.6)
摘要
这篇文章介绍了一个企业系统中的字段权限解析方案,通过规则表与命中记录表(biz_rule_hit)联动,实现对业务数据的动态权限控制。流程包括替换用户上下文变量、记录命中规则、查询业务数据并关联命中信息,最终在内存中合并字段权限等级(editable/view/masked/hidden),返回前端使用。该方案支持多规则叠加、权限优先级合并,并实现前后端解耦,适用于复杂权限场景的可审计、可扩展设计。
从规则表 + biz_rule_hit → JOIN 业务表 → 内存生成字段权限 → 返回前端,并且处理四种权限(editable/view/masked/hidden)逗号分割字段。
下面用 Java + 数据库 的完整示例:
1️⃣ 数据库:统一规则命中表
CREATE TABLE biz_rule_hit (biz_table_name VARCHAR(128) NOT NULL, -- 业务表名biz_id INT NOT NULL, -- 业务表主键rule_id INT NOT NULL, -- 命中规则IDuser_id INT NOT NULL, -- 用户IDhit_time DATETIME DEFAULT GETDATE(),PRIMARY KEY (biz_table_name, biz_id, rule_id, user_id)
);
- 一张表管理所有业务表的命中记录
biz_table_name
区分业务表
2️⃣ 读取规则表(替换用户上下文变量 + 解析字段)
class Rule {int ruleId;String evaluatedCondition; // 替换后的 SQL 条件List<String> editable;List<String> view;List<String> masked;List<String> hidden;
}int userId = 123;
int deptId = 10;
String bizTable = "biz_table";List<Rule> rules = jdbcTemplate.query("SELECT rule_id, condition_sql, editable, view, masked, hidden FROM rule_table WHERE biz_table = ? ORDER BY priority ASC",new Object[]{bizTable},(rs, rowNum) -> {Rule r = new Rule();r.ruleId = rs.getInt("rule_id");r.evaluatedCondition = rs.getString("condition_sql").replace("@UserID", String.valueOf(userId)).replace("@DeptID", String.valueOf(deptId));r.editable = Arrays.asList(rs.getString("editable").split(","));r.view = Arrays.asList(rs.getString("view").split(","));r.masked = Arrays.asList(rs.getString("masked").split(","));r.hidden = Arrays.asList(rs.getString("hidden").split(","));return r;}
);
3️⃣ 写入 biz_rule_hit
命中表
// 先删除该用户该业务表旧记录
jdbcTemplate.update("DELETE FROM biz_rule_hit WHERE user_id = ? AND biz_table_name = ?", userId, bizTable);// 插入命中记录
StringBuilder sqlInsertHits = new StringBuilder();
for(Rule rule : rules){sqlInsertHits.append("INSERT INTO biz_rule_hit (biz_table_name, biz_id, rule_id, user_id) ").append("SELECT '").append(bizTable).append("', b.id, ").append(rule.ruleId).append(", ").append(userId).append(" FROM ").append(bizTable).append(" b WHERE ").append(rule.evaluatedCondition).append(";");
}
jdbcTemplate.execute(sqlInsertHits.toString());
- 命中表存储 业务表名 + biz_id + rule_id + user_id
- 可以长期保存,支持审计
4️⃣ 查询业务表 + JOIN 命中表
String sqlQuery = "SELECT b.*, r.rule_id " +"FROM " + bizTable + " b " +"LEFT JOIN biz_rule_hit r " +"ON r.biz_id = b.id AND r.biz_table_name = ? AND r.user_id = ?";List<Map<String,Object>> bizData = jdbcTemplate.queryForList(sqlQuery, bizTable, userId);
rule_id
为 NULL → 没命中规则- LEFT JOIN 保证业务表所有行都返回
5️⃣ 内存生成字段权限(合并四种权限等级)
Map<String, Integer> levelMap = Map.of("hidden", 0,"masked", 1,"view", 2,"editable", 3
);Map<Integer, Map<String, String>> bizPermissions = new HashMap<>();for(Map<String,Object> row : bizData){int bizId = (Integer) row.get("id");bizPermissions.putIfAbsent(bizId, new HashMap<>());Integer ruleId = (Integer) row.get("rule_id");if(ruleId == null) continue; // 没命中规则// 找到规则对象Rule rule = rules.stream().filter(r -> r.ruleId == ruleId).findFirst().orElse(null);if(rule == null) continue;// 更新每个字段权限updatePermission(bizPermissions.get(bizId), rule.editable, "editable", levelMap);updatePermission(bizPermissions.get(bizId), rule.view, "view", levelMap);updatePermission(bizPermissions.get(bizId), rule.masked, "masked", levelMap);updatePermission(bizPermissions.get(bizId), rule.hidden, "hidden", levelMap);
}// 工具方法
void updatePermission(Map<String,String> permMap, List<String> fields, String newLevel, Map<String,Integer> levelMap){for(String field : fields){String current = permMap.getOrDefault(field, "hidden");if(levelMap.get(newLevel) > levelMap.get(current)){permMap.put(field, newLevel);}}
}
- editable > view > masked > hidden
- 多条规则叠加时取最大权限
6️⃣ 返回前端
List<Map<String,Object>> result = bizData.stream().map(row -> {int bizId = (Integer) row.get("id");row.put("permissions", bizPermissions.getOrDefault(bizId, Collections.emptyMap()));return row;}).collect(Collectors.toList());
- 前端直接使用
permissions
控制字段显示/编辑/脱敏 - 完全透明,不需要解析 SQL 规则
✅ 总结流程
- 查询规则表 → 替换用户上下文 → 解析字段名
- 写入统一
biz_rule_hit
表 - 查询业务表 + LEFT JOIN 命中表 → 得到命中规则
- 内存合并字段权限(四种等级)
- 返回前端
- 一张
_rule_hit
表管理所有业务表 - 支持用户变量、权限等级合并、多条规则叠加
- 前端拿到
permissions
即可控制字段