j_security_check表单认证错误重定向导致404问题咨询
看起来你遇到的是容器管理认证(FORM登录)结合手动重定向错误页导致的路径问题,我来帮你拆解一下:
问题根源
当你在凭证错误后重定向回登录页时,浏览器地址栏会更新为登录页的URL(比如/app/login.jsf?wrongCredentials=true)。如果你的登录表单的action是相对路径(比如只写了j_security_check),那么表单提交时会把这个相对路径拼在当前地址栏的URL后面,变成/app/login.jsf/j_security_check——而容器期望的是直接提交到上下文根下的/app/j_security_check,自然就会返回404了。
另外,手动重定向也会绕过容器FORM认证的默认错误处理逻辑,导致容器无法正确识别后续的登录请求。
解决方案
方案1:让容器自动处理错误页(推荐)
放弃手动重定向,直接在web.xml里配置容器的FORM错误页,容器会用转发而不是重定向的方式跳转到登录页,这样地址栏不会变,表单提交路径也不会出错:
- 修改
web.xml的登录配置:
<login-config> <auth-method>FORM</auth-method> <form-login-config> <form-login-page>/login.xhtml</form-login-page> <!-- 直接把错误页指向登录页,并带参数标识错误 --> <form-error-page>/login.xhtml?login_error=1</form-error-page> </form-login-config> </login-config>
- 在登录页
login.xhtml中根据参数渲染错误提示:
<h:panelGroup rendered="#{not empty param.login_error}"> <p style="color:red;">用户名或密码错误,请重新输入!</p> </h:panelGroup> <!-- 表单action保持默认的j_security_check即可,容器会自动处理路径 --> <form action="j_security_check" method="POST"> <h:inputText id="j_username" /> <h:inputSecret id="j_password" /> <h:commandButton type="submit" value="登录" /> </form>
方案2:给表单设置绝对路径(适合必须用重定向的场景)
如果你一定要保留重定向的逻辑,那必须确保表单的action是相对于上下文的绝对路径,这样无论登录页是怎么跳转过来的,都会提交到正确的地址:
在登录页中修改表单action:
<form action="#{request.contextPath}/j_security_check" method="POST"> <!-- 其余表单元素不变 --> </form>
#{request.contextPath}会自动获取你的应用上下文根(比如/app),这样表单提交的目标就是/app/j_security_check,不会出现路径拼接错误。
方案3:用请求属性传递错误状态(替代URL参数)
如果不想在URL里暴露错误参数,可以把错误状态放在请求属性中,用转发而不是重定向的方式跳转到登录页:
在处理错误的代码中:
// 不要用sendRedirect,改用转发 request.setAttribute("wrongCredentials", true); request.getRequestDispatcher("/login.xhtml").forward(request, response);
然后在登录页中读取请求属性:
<h:panelGroup rendered="#{requestScope.wrongCredentials}"> <p style="color:red;">用户名或密码错误,请重新输入!</p> </h:panelGroup>
这种方式同样不会改变地址栏,表单提交路径也能保持正确。
内容的提问来源于stack exchange,提问作者Pendula

