必须用AFTER LOGON而非BEFORE LOGON,因BEFORE阶段USER函数不可用且无法获取会话上下文;AFTER阶段认证已完成,USER可靠,时间判断才有效。

直接用 AFTER LOGON ON DATABASE 触发器是最可行、最可控的方式,但必须限定用户名、校验时间逻辑、避开 DBA 用户,否则可能把自己锁在外面。
为什么必须用 AFTER LOGON 而不是 BEFORE LOGON
BEFORE LOGON 触发器在身份认证完成前执行,此时 USER 函数不可用(返回空或报错),也无法读取会话上下文信息;而 AFTER LOGON 已完成认证,USER 可靠,且能安全调用 TO_CHAR(SYSDATE, ...)。实测中用 BEFORE 写的时间判断基本都失效,甚至导致所有用户登录失败。
怎么写才不误锁 DBA 或全站用户
核心是显式限定目标用户,并跳过高权限账户:
- 必须用
IF USER = 'REPORT_USER' THEN,不能只写IF USER IN ('REPORT_USER', 'ANALYST') THEN就完事——漏掉一个就可能锁错人 - 显式排除
SYS、SYSTEM等 DBA 用户:IF USER IN ('SYS','SYSTEM') THEN RETURN;,否则触发器一启用,你连sqlplus / as sysdba都进不去 - 时间判断别硬编码周几含义:先查当前数据库的
NLS_TERRITORY设置,执行SELECT TO_CHAR(SYSDATE, 'D') FROM DUAL;确认周日=1 还是周一=1,再写v_day IN (2,3,4,5,6)这类条件 - 小时比较必须转成数字:
TO_NUMBER(TO_CHAR(SYSDATE, 'HH24')),别用字符串比较'09'和'17',否则'9' > '17'会成立
常见错误现象与对应修复
这些坑在生产环境里反复出现,不是理论问题:
- 现象:
ORA-00604: error occurred at recursive SQL level 1+ORA-01031: insufficient privileges—— 触发器里尝试写日志表(如INSERT INTO audit_log...)但没给SYS授予INSERT ANY TABLE权限;修复:要么去掉 DML,要么提前授权并确保表在SYS下 - 现象:非工作时间仍能登录,但查
V$SESSION发现LOGON_TIME是昨天 —— 触发器只拦新连接,已有会话不受影响;修复:若需实时中断,得配合DBMS_SCHEDULER定时扫描V$SESSION并ALTER SYSTEM KILL SESSION - 现象:周一早上 8:59 登录成功,9:00 才报错 —— 时间判断用了
BETWEEN 9 AND 17,但HH24返回的是整数,9表示 09:00–09:59,正确写法应是v_hour BETWEEN 9 AND 16(覆盖 09:00–16:59),或改用字符串比较TO_CHAR(SYSDATE, 'HH24:MI') BETWEEN '09:00' AND '17:00'
真正难的不是写触发器,而是验证它在不同 NLS 设置、不同用户角色、不同连接方式(JDBC/SQL*Plus/ODBC)下是否始终按预期拦截——上线前务必用非 DBA 账户在周末、凌晨、边界时刻反复测试。


















