MySQL原生不支持行级访问控制(RLS),需通过SQL SECURITY DEFINER视图+用户映射表实现;关键是以CURRENT_USER()关联user_role_mapping表过滤,禁用USER()和应用传参,配合CHECK OPTION与角色权限加固。

MySQL 原生不支持行级访问控制(RLS),必须通过视图 + SQL SECURITY DEFINER + 用户隔离逻辑组合实现,否则直接授予权限等于裸奔。
用 VIEW + DEFINER 模拟行级过滤
核心思路是让每个用户只能看到自己有权限的行,而不是靠应用层拼 WHERE 条件(容易绕过)。关键在于视图定义时绑定当前用户身份,并由高权限 DEFINER 执行过滤逻辑。
-
CREATE VIEW user_orders AS SELECT * FROM orders WHERE user_id = USER();不可靠——USER()返回连接凭据,不是业务用户 ID;应改用CURRENT_USER()或更稳妥的映射表 - 正确做法:建一张
user_role_mapping表,存db_user→business_user_id映射,视图中用(SELECT business_user_id FROM user_role_mapping WHERE db_user = CURRENT_USER())关联过滤 - 视图必须用
SQL SECURITY DEFINER创建,且 DEFINER 账号需有orders表的 SELECT 权限;普通用户只被授予对该视图的 SELECT 权限 - 避免在视图里用函数(如
MD5()、自定义函数),否则可能使 MySQL 无法下推条件,导致全表扫描
WHERE 条件里不能依赖应用传入的 user_id
如果应用代码里写 SELECT * FROM orders WHERE user_id = ? 并把当前登录用户 ID 当参数传进去,就完全脱离数据库层防护——SQL 注入、调试模式绕过、内部工具直连都会失效。
- 所有敏感表禁止开放给应用直接查询,只暴露视图
- 应用连接 MySQL 必须使用专用账号(如
app_user_123),该账号仅能查对应视图,不能 SHOW CREATE VIEW、不能查系统表 - 若业务需多租户共享数据(如 SaaS),
tenant_id字段必须作为联合索引最左列,否则视图过滤后仍可能慢查询
替代方案:MySQL 8.0+ 的 CHECK OPTION 和角色权限配合
单纯靠视图不够防误操作,需要叠加约束和角色管理。
- 创建视图时加
WITH CHECK OPTION,防止用户通过视图 INSERT/UPDATE 写入非本人数据(例如INSERT INTO user_orders (user_id, amount) VALUES (999, 100)会被拒绝) - 用
CREATE ROLE分离权限组,比如role_analyst只能查聚合视图,role_support可查客户脱敏字段视图,再用GRANT role_x TO 'user@%' - 注意:
CURRENT_ROLE()在视图里不可用,所以角色差异必须体现在视图定义或额外映射表中,不能靠运行时判断角色名
真正难的是把“谁能看到哪几行”这个业务规则稳定映射到数据库对象上——映射表要维护、视图要随业务字段变更重编译、DEFINER 账号密码轮换会影响所有视图。别指望一套 SQL 解决所有 RLS 场景,先守住最危险的那几张表。


















