权限即数据:企业系统中的字段级访问控制架构实战(β=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 规则

✅ 总结流程

  1. 查询规则表 → 替换用户上下文 → 解析字段名
  2. 写入统一 biz_rule_hit
  3. 查询业务表 + LEFT JOIN 命中表 → 得到命中规则
  4. 内存合并字段权限(四种等级)
  5. 返回前端
  • 一张 _rule_hit 表管理所有业务表
  • 支持用户变量、权限等级合并、多条规则叠加
  • 前端拿到 permissions 即可控制字段

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/diannao/98713.shtml
繁体地址,请注明出处:http://hk.pswp.cn/diannao/98713.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Python爬虫实战:研究Specialty Plots模块,构建空气质量监测数据采集和分析系统

1. 引言 1.1 研究背景 随着全球城市化进程的加速和工业的快速发展,空气质量问题已成为影响人类健康和生态环境的重要因素。世界卫生组织数据显示,全球超过 90% 的人口生活在空气质量超标的环境中,空气污染每年导致约 700 万人过早死亡。准确、及时地获取和分析空气质量数据…

字典树算法

一、什么是Trie&#xff1f; Trie&#xff08;发音为"try"&#xff09;&#xff0c;也称为字典树、前缀树&#xff0c;是一种多叉树结构&#xff0c;专门用于高效存储和检索字符串集合。其核心特点是共享字符串的公共前缀&#xff0c;从而大幅减少冗余存储&#xff0…

Laya使用VideoNode动态加载视频,可以自定义播放视频此处以及位置

export class VideoCommand {video: Laya.VideoNode;public duration: number 0;/*** param videoPos 视频位置* param videoSize 视频大小*/public constructor(videoPos: Laya.Vector2, videoSize: Laya.Vector2) {this.video new Laya.VideoNode;//添加到舞台 1是场景中的…

yum localinstall安装本地包

yum localinstall 是一个用于安装本地 RPM 包并自动处理依赖关系的命令。当你有一个或多个本地的 RPM 包需要安装,又希望 yum 能帮你解决可能存在的依赖问题时,这个命令就非常有用。下面我会详细解释它的用法和注意事项。 🖥️ 命令基本用法 yum localinstall 命令的基本…

LeetCode 面试经典 150 题:轮转数组(三次翻转法详解 + 多解法对比)

在数组类算法题中&#xff0c;“轮转数组” 是一道考察 “原地操作” 与 “逻辑转换” 能力的经典题目。所谓 “轮转”&#xff0c;是指将数组元素向右移动指定步数&#xff0c;且超出数组长度的元素需 “循环” 到数组开头。这道题的最优解 ——三次翻转法&#xff0c;能以 O …

网络编程---TCP

1.TCP&#xff1a;传输控制协议&#xff0c;位于传输层2.TCP的特性&#xff1a;a.使用流式套接字&#xff0c;数据连续&#xff0c;有顺序b.TCP是可靠传输&#xff0c;有有应答机制ACK&#xff0c;即收到数据后会明确告知发送方已收到数据&#xff1b;若发送方没有在预计时间收…

对计算机网络模型的理解

文章目录 目录 前言 一、Internet 的核心特点 二、Internet 的组成结构 1. 硬件基础&#xff1a;网络运行的 “物理载体” 2. 软件支撑&#xff1a;网络运行的 “功能桥梁” 3. 协议规则&#xff1a;网络运行的 “通用语言” 三、OSI 七层参考模型&#xff08;理论标准&…

每日一算:分发糖果

在算法面试中&#xff0c;“分发糖果” 是一道经典的贪心算法应用题&#xff0c;核心考察对 “局部最优推导全局最优” 的理解。本文将从问题分析出发&#xff0c;提供两种主流解题思路&#xff0c;并附上 C 实现代码&#xff0c;帮助你彻底掌握这道题。一、问题重述题目要求有…

【WorkManager】无法在 Direct Boot 模式下初始化

【WorkManager】无法在 Direct Boot 模式下初始化一、问题描述二、问题分析2.1 关于 Direct Boot 模式2.2 支持 Direct Boot 模式2.3 手动初始化 WorkManager 组件2.4 WorkManager 不支持 Direct Boot 的官方修改三、解决方案一、问题描述 在使用 WorkManager 库来实现开机上报…

Hybrid应用性能优化实战分享(本文iOS 与 H5为例,安卓同理)

前言在移动应用开发中&#xff0c;Hybrid 架构因其跨平台特性和开发效率优势被广泛采用。然而&#xff0c;WebView 的性能问题一直是开发者面临的挑战。本文将基于实际项目经验&#xff0c;分享 iOS Hybrid 应用的核心优化策略&#xff0c;涵盖 WebView 池化、预加载、用户体验…

点积、叉积、矩阵行列式详解、线性相关与线性无关、矩阵的秩、矩阵可逆与不可逆详解

1.向量 1.1 点积&#xff08;Dot Product&#xff09; 1.1.1 定义 点积是在求一个标量&#xff0c;点积结果没有方向。 对于两个向量u(u1,u2,u3),v(v1,v2,v3)\bold{u}(u_1,u_2,u_3),\bold{v}(v_1,v_2,v_3)u(u1​,u2​,u3​),v(v1​,v2​,v3​) 点积定义为&#xff1a;u⋅vu1v1u…

Mac安装nvm详细教程(超简单)

本章教程,主要介绍如何在Mac操作系统上安装nvm. 我们使用官方一键安装脚本,完成安装 一、安装步骤 curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.3/install.sh | bash配置环境变量,编辑.zshrc文件 vim .zshrcexport NVM_DIR="$(

【selenium】网页元素找不到?从$(‘[placeholder=“手机号“]‘)说起

网页元素找不到&#xff1f;从$(‘[placeholder“手机号”]’)说起总结&#xff1a;控制台不骗人&#xff0c;元素选不到&#xff0c;八成是写法、时机或环境的问题。我们在写网页自动化脚本或者调试页面的时候&#xff0c;经常遇到一个让人头疼的问题&#xff1a;明明元素就在…

SSE 模仿 GPT 响应

后端代码 const express require(express) const cors require(cors);const app express(); app.use(cors()); const port 3000;app.listen(port, () > {console.log(Server running at http://localhost:${port}/); });const msg 全国同胞们&#xff0c; 尊敬的各位国…

MAC 多个版本 JDK进行切换

1.查看本机所有的jdk/usr/libexec/java_home -V2、打开bash_profile文件。可以在终端vim ~/.bash_profile打开&#xff0c;也可以打开访达shiftcmdG然后输入/Users/mac/.bash_profile&#xff08;本机bash_profile的路径&#xff09;加入新的环境变量格式如下&#xff08;参考我…

shell 中 expect 详解

一、概述Expect是一个免费的编程工具语言&#xff0c;用来实现自动和交互式任务进行通信&#xff0c;而无需人的干预。Expect的作者DonLibes在1990年开始编写Expect时对Expect做有如下定义&#xff1a;Expect是一个用来实现自动交互功能的软件套件。通过expect系统管理员可以创…

第4讲 机器学习基础概念

机器学习作为人工智能的子领域&#xff0c;专注于训练计算机算法自动发现数据中的模式与关联关系。以下是其核心基础概念&#xff1a;4.1 数据数据是机器学习的基石。缺乏数据&#xff0c;算法将无从学习。数据可呈现为结构化数据&#xff08;如电子表格、数据库&#xff09;和…

Go组合式继承:灵活替代方案

Go 语言没有传统面向对象编程中的继承机制&#xff0c;但通过组合和接口实现类似功能。Go 更提倡组合优于继承的设计原则&#xff0c;这种设计方式更灵活且易于维护。结构体组合&#xff08;伪继承&#xff09;通过嵌套结构体实现类似继承的效果。子结构体可以直接访问父结构体…

Verilog三段式FSM,实现十字路口红绿灯

运行环境&#xff1a;VCS verdi状态说明&#xff1a;S0 &#xff1a; 初始状态 S1 &#xff1a; 东西方向绿灯亮&#xff0c;南北方向红灯亮&#xff1b;点亮30周期 S2 &#xff1a; 东西方向黄灯亮&#xff0c;南北方向红灯亮&#xff1b;点亮2 周期 S3 &#xff1a; 东西方向…

java 将pdf转图片

如何将pdf文件转为图片 import org.apache.pdfbox.pdmodel.PDDocument; import org.apache.pdfbox.rendering.PDFRenderer; import javax.imageio.ImageIO; import java.awt.image.BufferedImage; import java.io.File; import java.io.IOException; public class Pdf2Png {/**…