摘要
β=0.8 在 β=0.7 的“三层合并模型”之上,取消命中表,将规则下推为 SQL CASE,在查询阶段直接返回命中规则的内存下标串;应用层继续执行表级基线与字段默认的合并、脱敏与审计,并新增稳定排序与 keyset 策略,系统性解决分页漂移与统计不一致。本文同时集成 β=0.7 的“极限规则应用”代码路径(封顶/兜底/deny)以保持治理能力的一致性与可回滚性。
关键字
- 字段级权限控制
- 表级基线封顶
- 规则下推SQL化
- 动态SQL CASE命中
- 权限感知与Keyset分页
- 脱敏与可写审计
β=0.7 基线与极限规则回顾
- **表级基线封顶:**按主体维度配置表级上限,限制字段最大可达权限。
- **字段固定默认:**无命中时的字段默认等级,形成“下限兜底”。
- **规则提升叠加:**多规则命中按字段取最大提升。
- **极限规则应用:**以“最小-最大”模型收敛,先合并默认与提升,再施加全局封顶与可选 deny,将结果拉回“安全边界”。
- **处理顺序:**表级封顶 → 字段默认 → 规则提升 → 再封顶 → deny → 脱敏 → 审计。
命中识别前移与分页一致性(β=0.8)
- **规则内存化与编号:**规则加载入内存稳定编号 0…N−1,每条含“SQL 条件片段 + 字段→等级映射”。
- **SQL CASE 下推:**一次查询返回业务行与命中规则下标串,如 “0,2,”。
- **权限感知分页:**同一条 SQL 内完成 WHERE/ORDER BY/LIMIT(或 keyset),不在页内做行级再过滤,避免漂移;必要统计用窗口函数或并行 COUNT。
- **跨库与实时性:**无命中表,降低跨库耦合;规则更新即刻生效。
- 以上在 β=0.7 的思路基础上将“命中识别”侧移数据库,保留合并与审计策略不变。
核心 SQL 示例(可跨方言适配)
- MySQL:
SELECT
b.*,
CONCAT(
CASE WHEN amount > 1000 AND status = 'A' THEN '0,' ELSE '' END,
CASE WHEN region = 'CN' THEN '1,' ELSE '' END,
CASE WHEN vip = 1 THEN '2,' ELSE '' END
) AS hit_rule_indexes
FROM biz_table b
WHERE /* 业务条件 */
ORDER BY created_at DESC, id DESC
LIMIT :limit OFFSET :offset;
- PostgreSQL/Oracle(使用 ||):
SELECT
b.*,
(CASE WHEN amount > 1000 AND status = 'A' THEN '0,' ELSE '' END ||
CASE WHEN region = 'CN' THEN '1,' ELSE '' END ||
CASE WHEN vip = 1 THEN '2,' ELSE '' END) AS hit_rule_indexes
FROM biz_table b
WHERE /* 业务条件 */
ORDER BY created_at DESC, id DESC
OFFSET :offset ROWS FETCH NEXT :limit ROWS ONLY;
- SQL Server(CONCAT 或 +):
SELECT
b.*,
CONCAT(
CASE WHEN amount > 1000 AND status = 'A' THEN '0,' ELSE '' END,
CASE WHEN region = 'CN' THEN '1,' ELSE '' END,
CASE WHEN vip = 1 THEN '2,' ELSE '' END
) AS hit_rule_indexes,
COUNT(*) OVER() AS total_count
FROM biz_table b
WHERE /* 业务条件 */
ORDER BY created_at DESC, id DESC
OFFSET @offset ROWS FETCH NEXT @limit ROWS ONLY;
以上“表级基线、字段默认、规则叠加、封顶与审计”的方法论延续自 β=0.7 的合并模型。
合并引擎(集成 β=0.7 极限规则应用)
说明:以下合并引擎同时支持 β=0.8 的“命中下标串”与 β=0.7 的“单条命中或多条命中列表”,并显式实现“极限规则应用”(全局封顶 cap、字段兜底 floor 与 deny 覆盖),确保在任何命中组合下结果稳定落入安全区间。
// 等级顺序映射:hidden=0, masked=1, view=2, editable=3(示例)
static final Map<String, Integer> LEVEL = Map.of(
"hidden", 0, "masked", 1, "view", 2, "editable", 3
);
static String levelName(int v) {
for (var e : LEVEL.entrySet()) if (e.getValue() == v) return e.getKey();
return "hidden";
}
// 规则定义(每条规则提供“字段 -> 目标等级”映射)
class Rule {
int index; // 内存编号(0..N-1)
Map<String, String> fieldLv; // 字段 -> 等级名
Map<String, Integer> fieldMax; // 可选:字段局部封顶(极限规则)
Map<String, Integer> fieldMin; // 可选:字段局部兜底(极限规则)
// ... 其它元数据(如命中条件 SQL 片段、租户范围等)
}
// 合并上下文(来自 β=0.7 的“三层合并模型”,并加入极限规则位)
class MergeContext {
int tableCap; // 表级封顶(上限)
Map<String, Integer> fieldDefault; // 字段默认(下限)
Map<String, Integer> denyCap; // 可选:字段级 deny 上限(更严)
Map<Integer, Rule> ruleIndexMap; // 规则编号 -> 规则
}
// 解析命中下标串("0,2," -> [0,2])
static Set<Integer> parseHits(String s) {
if (s == null || s.isEmpty()) return Set.of();
String t = s.endsWith(",") ? s.substring(0, s.length() - 1) : s;
if (t.isEmpty()) return Set.of();
Set<Integer> out = new LinkedHashSet<>();
for (String p : t.split(",")) if (!p.isBlank()) out.add(Integer.parseInt(p));
return out;
}
// 极限规则合并:floor(兜底) -> 提升max -> 局部min/max -> 全局cap -> deny
static Map<String, String> mergeRowPermissions(
Map<String, Object> row,
String hitRuleIndexes, // β=0.8 来源(命中下标串)
List<Integer> hitRuleList07, // β=0.7 兼容:命中ID列表(可空)
MergeContext ctx,
Set<String> allFields
) {
Set<Integer> hits = new LinkedHashSet<>();
hits.addAll(parseHits(hitRuleIndexes));
if (hitRuleList07 != null) hits.addAll(hitRuleList07); // 兼容 β=0.7
Map<String, Integer> result = new HashMap<>();
for (String f : allFields) {
// 1) 字段默认(下限)
int v = Math.min(ctx.tableCap, ctx.fieldDefault.getOrDefault(f, LEVEL.get("hidden")));
// 2) 规则提升(多规则取最大)
for (int idx : hits) {
Rule r = ctx.ruleIndexMap.get(idx);
if (r == null) continue;
String lvName = r.fieldLv.get(f);
if (lvName != null) v = Math.max(v, LEVEL.getOrDefault(lvName, v));
}
// 3) 局部极限(每条规则可定义字段局部 min/max,逐条收敛)
int localMin = Integer.MIN_VALUE, localMax = Integer.MAX_VALUE;
for (int idx : hits) {
Rule r = ctx.ruleIndexMap.get(idx);
if (r == null) continue;
if (r.fieldMin != null && r.fieldMin.containsKey(f))
localMin = Math.max(localMin, r.fieldMin.get(f));
if (r.fieldMax != null && r.fieldMax.containsKey(f))
localMax = Math.min(localMax, r.fieldMax.get(f));
}
if (localMin != Integer.MIN_VALUE) v = Math.max(v, localMin);
if (localMax != Integer.MAX_VALUE) v = Math.min(v, localMax);
// 4) 全局封顶(表级 cap)
v = Math.min(v, ctx.tableCap);
// 5) deny 覆盖(更严的上限)
if (ctx.denyCap != null && ctx.denyCap.containsKey(f))
v = Math.min(v, ctx.denyCap.get(f));
result.put(f, v);
}
// 6) 返回字符串等级(用于脱敏与审计)
Map<String, String> named = new HashMap<>();
result.forEach((k, val) -> named.put(k, levelName(val)));
return named;
}
- 要点说明:
- **极限规则位:**在每条规则中允许配置字段级
fieldMin/fieldMax
,实现“局部兜底/封顶”,与全局表级 cap、deny 叠加,保证任何叠加下都能收敛。 - **双栈兼容:**既支持 β=0.8 的命中下标串,也兼容 β=0.7 的命中 ID 列表输入路径,便于灰度与回滚。
- **顺序严格:**默认下限 → 提升 → 局部极限 → 全局封顶 → deny;顺序改变会破坏安全边界。
- **极限规则位:**在每条规则中允许配置字段级
脱敏与审计接入点
- **脱敏:**在字段达至少 view 时按字段策略执行掩码;masked 与 view 的策略互斥且幂等。
- **审计:**对 editable 字段记录“用户-对象-字段-时间-上下文”访问与变更日志;保留命中下标串用于追溯。
- **β=0.7 继承:**上述实践直接承接 β=0.7 的审计与脱敏内聚思路,无需改动域模型。
运维与灰度
- **规则集版本化:**同版本内编号稳定;以配置中心下发 CASE 模板与规则映射。
- **分页稳定:**固定 ORDER BY 键(如 created_at DESC, id DESC);大表使用 keyset 避免 OFFSET 大扫描。
- **回滚双开关:**查询层(CASE 模板)与应用层(解析命中串)各自可回退到 β=0.7 路径。
结语
β=0.8 将“命中识别”前移到数据库层,以 CASE 生成命中下标串,解决跨库带来的复杂度与时延,同时通过稳定排序与 keyset 策略解决分页漂移;在应用层完整复用 β=0.7 的“三层合并模型”与“极限规则应用”代码,确保任何规则叠加都能在安全边界内收敛,达成“性能、治理、可审计”的工程平衡。
参考:β=0.7 合并模型概念、表级基线/字段默认、内存合并与审计脱敏思路等背景内容。