触发器不能用于过滤select,sql标准不支持before/after select触发器;权限校验需分操作类型,insert/update/delete中须显式传入业务用户id而非依赖数据库连接身份,并通过rls、视图或会话变量实现安全控制。

触发器里不能直接过滤 SELECT,别白费劲
SQL 标准不支持 BEFORE SELECT 或 AFTER SELECT 触发器。PostgreSQL 和 MySQL 都会直接报错:ERROR: syntax error at or near "SELECT"。想靠触发器拦住查询、动态过滤返回结果,这条路根本走不通。
真正可行的读权限控制路径只有两条:
- PostgreSQL:启用行级安全(RLS),用
CREATE POLICY定义基于当前上下文的过滤条件 - SQL Server / MySQL:用视图封装逻辑,配合
SESSION_CONTEXT(SQL Server)或应用层传参 +WHERE拼接(MySQL)
硬要在触发器里写“查权限表再决定放不放行”,不仅无效,还会误导团队把精力浪费在不可行方案上。
INSERT/UPDATE/DELETE 中校验权限,必须显式传用户 ID
别信 CURRENT_USER、USER() 或 SUSER_SNAME() —— 它们返回的是数据库连接身份,不是业务用户。比如 MySQL 的 USER() 是 'app@10.2.3.4',PostgreSQL 的 current_user 是角色名 'app_rw',跟员工 ID 'u123' 完全无关。
正确做法是让应用层提前注入业务用户标识:
一款AI工具,主要用于一款基于 Rust 的快速无头浏览器自动化命令行工具(CLI),支持 Node.js 回退机制,可使 AI agent 通过结构化命令实现页面导航、点击、输入及截图,适合需要提升相关任务效率的用户。
- PostgreSQL:执行
SET LOCAL app.current_user_id = 'u123',触发器内用current_setting('app.current_user_id', true) - MySQL:执行
SET @current_user_id = 'u123',触发器内直接引用@current_user_id - SQL Server:执行
EXEC sp_set_session_context @key = N'user_id', @value = 'u123',触发器内用SESSION_CONTEXT(N'user_id')
没这步,触发器里的权限判断全是空中楼阁。
校验逻辑要分操作类型,UPDATE 最容易漏判
权限校验不是“看用户能不能操作这张表”,而是“这条记录归不归当前用户管”。关键字段(如 owner_id)必须参与比对,且不同操作类型规则不同:
-
INSERT:只校验NEW.owner_id = 当前用户ID -
UPDATE:必须同时校验OLD.owner_id = 当前用户ID(确保原属自己)且NEW.owner_id未被篡改(若业务禁止转交,则不允许修改该字段) -
DELETE:只校验OLD.owner_id = 当前用户ID
常见错误是 UPDATE 只检查 NEW.owner_id,结果用户 A 把用户 B 的订单 owner_id 改成自己,绕过权限控制。
触发器里查权限表 = 自找死路
在触发器中 SELECT FROM permission_config WHERE user_id = ... 看似灵活,实则危险:
- 高并发下锁住权限表,导致整个 DML 链路阻塞
- 无法利用索引优化复杂规则(如“部门主管可看本部门所有订单”)
- 权限逻辑分散在触发器和配置表之间,调试和审计成本陡增
更稳的做法是:把权限判定收口到应用层,或用 RLS / 视图 + 上下文变量实现静态化过滤。触发器只做简单等值校验,别让它承担策略解析职责。










