必须手动绑定、显式授权、逐层验证,缺一不可——否则 ora12c_verify_function 就是摆设;需确认 default profile 已启用该函数、函数在 sys 下且状态为 valid、已授 execute 权限给 public、用户实际使用 default profile,且注意 al32utf8 字符集下 unicode 特殊字符可能被跳过校验。

必须手动绑定、显式授权、逐层验证,缺一不可——否则 ORA12C_VERIFY_FUNCTION 就是摆设。
确认 DEFAULT profile 是否已启用密码校验函数
很多人改完就以为生效了,结果新用户还能设 oracle123。别猜,直接查:
SELECT limit FROM dba_profiles WHERE profile = 'DEFAULT' AND resource_name = 'PASSWORD_VERIFY_FUNCTION';
返回 NULL 或空值?说明没启用。返回函数名(如 ORA12C_VERIFY_FUNCTION)?继续往下查是否真能用。
- 函数必须在
SYSschema 下,且状态为VALID - 执行:
SELECT owner, object_name, status FROM dba_objects WHERE object_name = 'ORA12C_VERIFY_FUNCTION' AND object_type = 'FUNCTION';
- 若
status不是VALID,编译会通过,但ALTER USER ... IDENTIFIED BY时静默失败,只报ORA-28003,不提示原因
运行 utlpwdmg.sql 后为什么仍不生效
脚本执行成功 ≠ 策略落地。常见断点有三个:
-
@?/rdbms/admin/utlpwdmg.sql只创建函数并修改DEFAULTprofile 的PASSWORD_VERIFY_FUNCTION参数,但不会自动把已有用户从其他 profile 切换过来 - 函数创建后必须显式授权:
GRANT EXECUTE ON ORA12C_VERIFY_FUNCTION TO PUBLIC;
否则非SYS用户调用时静默失败(无错误日志,只报ORA-28003) - 检查用户实际绑定的 profile:
SELECT username, profile FROM dba_users WHERE username NOT IN ('SYS','SYSTEM');如果用户绑的是自定义 profile,DEFAULT的设置对它完全无效
字符集影响:AL32UTF8 下特殊字符可能被忽略
ORA12C_VERIFY_FUNCTION 默认要求至少 8 位、含大小写字母+数字+特殊字符,但若数据库字符集是 AL32UTF8,部分 Unicode 特殊字符(如中文标点、emoji、全角符号)会被跳过校验——它实际只按 ASCII 范围判断字符类型。
- 测试方法:用
!@#¥%……&*(含中文符号)设密码,很可能通过;换成!@#$%^&*才真正触发校验 - 这不是 bug,是 Oracle 对多字节字符处理的固有限制;生产环境建议统一用 ASCII 范围内的特殊字符
- 若业务强制要求支持 Unicode 特殊字符,必须手写自定义函数,并在内部用
ASCIISTR()或正则明确限定校验范围
自定义函数最容易踩的三个硬性坑
手写 verify_function 时,以下任意一点出错,都会导致函数编译通过但运行时失效:
- 函数签名必须严格为:
FUNCTION my_verify (username IN VARCHAR2, password IN VARCHAR2, old_password IN VARCHAR2) RETURN BOOLEAN
多一个参数、少一个IN、返回NUMBER都不行 - 函数体内禁止出现 DML(
INSERT/UPDATE)、DBMS_OUTPUT.PUT_LINE、自治事务;调试只能靠CREATE TABLE记日志(不推荐)或提前用SELECT ... FROM DUAL验证逻辑分支 - 不能依赖外部对象(如表、视图、包),所有逻辑必须内聚;若需查历史密码,只能用
USER_HISTORY$(需SYS权限)且必须加异常处理,否则任何未捕获错误都转为ORA-28003
真正难的不是写逻辑,而是让 Oracle 内核信任并稳定调用它——所有路径都得返回 BOOLEAN,且不能抛出未声明异常。











