APEX应用修改密码功能异常:旧密码校验始终不匹配
我在APEX对象浏览器中有一张名为CSD_USERS的表,结构如下:
ID NUMBER USERNAME VARCHAR2(250) PASSWORD VARCHAR2(15) ACCESS_TYPE NUMBER
注:PASSWORD字段已预先填充数据。
在共享组件\列表\列表详情中,我创建了名为Change Password的列表,其父列表条目设置为&APP_USER.。
我还创建了一个名为Change Password的页面,包含3个带PL/SQL代码验证的项:
- P14_OLD_PASSWORD的验证代码:
Declare v_pass Varchar2(30); Begin select PASSWORD into v_pass from CSD_USERS where ID = :APP_USER and Password = :P14_OLD_PASSWORD; RETURN TRUE; EXCEPTION WHEN OTHERS THEN RETURN FALSE; end;
- P14_NEW_PASSWORD的验证代码:
BEGIN IF 5 <= LENGTH(:P14_NEW_PASSWORD) AND LENGTH(:P14_NEW_PASSWORD) <= 15 THEN IF REGEXP_LIKE(:P14_NEW_PASSWORD, '^.*[0-9]') THEN IF REGEXP_LIKE(:P14_NEW_PASSWORD, '^.*[a-z]', 'c') THEN IF REGEXP_LIKE(:P14_NEW_PASSWORD, '^.*[A-Z]', 'c') THEN IF REGEXP_LIKE(:P14_NEW_PASSWORD, '^.*[!@#$%^&*()_]', 'c') THEN RETURN ''; ELSE RETURN 'Password must have a special character'; END IF; ELSE RETURN 'Password must have at least one uppercase character'; END IF; ELSE RETURN 'Password must have at least one lowercase character'; END IF; ELSE RETURN 'Password must have at least one numeric value'; END IF; ELSE RETURN 'Password length must be 5 or greater than 5 , Your password length is'||' '||LENGTH(:P14_NEW_PASSWORD); END IF; END;
- P14_RETYPE_NEW_PASSWORD_VALIDATION的验证规则:
V('P14_NEW_PASSWORD') = V('P14_RETYPE_NEW_PASSWORD')
该页面还有一个名为CHANGE_PASSWORD_PROCESS的流程,代码如下:
BEGIN UPDATE CSD_USERS SET PASSWORD = :P14_NEW_PASSWORD WHERE ID = :APP_USER AND PASSWORD = :P14_OLD_PASSWORD; END;
问题:测试时,即使我复制/输入正确的旧密码,系统始终提示旧密码不匹配。请问导致登录用旧密码与修改时输入的旧密码对比失败的原因是什么?
以下是几种可能导致旧密码验证失败的核心原因:
:APP_USER与表中ID字段不匹配
APEX的:APP_USER默认存储的是用户登录的用户名(即表中USERNAME字段),但你的SQL语句中用ID = :APP_USER进行匹配。如果表中ID是数字类型,而:APP_USER是字符串类型的用户名,会直接导致类型转换错误或匹配无结果。应将条件改为USERNAME = :APP_USER,或确认:APP_USER确实存储的是用户的ID值。密码存储为加密/哈希值,而非明文
若表中PASSWORD字段预先填充的是加密或哈希后的结果,而你输入的是明文旧密码,直接用Password = :P14_OLD_PASSWORD对比必然失败。需验证表中密码的存储形式,若为加密/哈希值,验证和更新流程都需要对输入的密码做相同的加密/哈希处理后再对比。输入项存在隐形空格
输入的旧密码可能前后带有隐形空格,而表中存储的密码无空格。可在验证代码中对输入值做trim处理,修改查询条件为Password = TRIM(:P14_OLD_PASSWORD),同时检查页面项P14_OLD_PASSWORD是否开启自动去除空格的设置。异常捕获过于宽泛
旧密码验证代码中WHEN OTHERS THEN RETURN FALSE会掩盖所有错误(比如:APP_USER匹配不到用户、类型转换错误等),导致任何错误都被判定为旧密码不匹配。建议修改为仅捕获NO_DATA_FOUND异常,其他异常抛出以方便排查:Declare v_pass Varchar2(30); Begin select PASSWORD into v_pass from CSD_USERS where ID = :APP_USER and Password = :P14_OLD_PASSWORD; RETURN TRUE; EXCEPTION WHEN NO_DATA_FOUND THEN RETURN FALSE; WHEN OTHERS THEN RAISE; end;大小写敏感差异
新密码验证开启了大小写敏感,但旧密码查询默认遵循数据库的大小写敏感设置。若数据库参数NLS_COMP/NLS_SORT为大小写不敏感,但表中密码是大小写敏感存储,或反之,都会导致对比失败。可尝试显式指定大小写规则,比如UPPER(Password) = UPPER(:P14_OLD_PASSWORD)(若密码大小写不敏感)。
内容的提问来源于stack exchange,提问作者Omatayo Holder

