基于 JSF 表单的身份验证 + 托管 Bean 登录不起作用
Posted
技术标签:
【中文标题】基于 JSF 表单的身份验证 + 托管 Bean 登录不起作用【英文标题】:JSF Form Based Authentication + Managed Bean login not working 【发布时间】:2014-06-01 04:14:23 【问题描述】:我想在Java EE 6 Turorial 之后实现托管 Bean 表单基本身份验证 我必须配置和构建所有必需的元素,例如登录表单、错误页面、web.xml 安全配置和 Tomcat 安全领域 (JDBC)。
问题是什么? 应该在托管 Bean 中调用 login() 方法的 commandButton 不起作用,我可以看到构造函数和 getter 被调用,但 login 方法和二传手不是。
有什么好奇怪的?如果我从 web.xml 中删除所有与安全相关的元素,重新启动应用程序并直接转到 login.xhtml 表单,login() 方法确实被调用了。
结论?如果使用托管 bean,JSF 实现中一定有一些东西会阻止这种基于表单的身份验证正常工作。
注意:常规的 j_security_check 基于表单的身份验证(不使用 JSF)工作正常。
有什么想法吗?
login.xhtml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html lang="en" xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core">
<f:view>
<h:head>
<title>Login Form</title>
</h:head>
<h:body>
<h2>Hello, please log in:</h2>
<h:form id="loginForm">
<h:messages style="color:red;margin:8px;" />
Username: <h:inputText value="#loginBean.username" />
<br />
Password: <h:inputSecret value="#loginBean.password" />
<br />
<h:commandButton id="loginButton" value="Login" action="#loginBean.login" />
</h:form>
</h:body>
</f:view>
</html>
LoginBean.java
package src;
import java.io.Serializable;
import javax.faces.application.FacesMessage;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.SessionScoped;
import javax.faces.context.FacesContext;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
@ManagedBean
@SessionScoped
public class LoginBean implements Serializable
/**
*
*/
private static final long serialVersionUID = 2951813936936766650L;
public LoginBean()
System.out.println("LoginBean()");
private String username;
private String password;
public String getUsername()
System.out.println("getUsername() returning: " + this.username);
return this.username;
public void setUsername(String username)
System.out.println("setUserName(" + username + ")");
this.username = username;
public String getPassword()
System.out.println("getPassword() returning: " + this.password);
return this.password;
public void setPassword(String password)
System.out.println("setPassword(" + password + ")");
this.password = password;
public String dummy()
System.out.println("dummy()");
return "dummy";
public String login()
System.out.println("login()");
FacesContext context = FacesContext.getCurrentInstance();
HttpServletRequest request = (HttpServletRequest) context.getExternalContext().getRequest();
try
request.login(this.username, this.password);
catch (ServletException e)
e.printStackTrace();
context.addMessage(null, new FacesMessage("Login failed."));
return "error";
return "index";
public void logout()
System.out.println("logout()");
FacesContext context = FacesContext.getCurrentInstance();
HttpServletRequest request = (HttpServletRequest) context.getExternalContext().getRequest();
try
request.logout();
catch (ServletException e)
e.printStackTrace();
context.addMessage(null, new FacesMessage("Logout failed."));
web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
id="WebApp_ID" version="3.0">
<display-name>FormBasedManagedBeanAuth</display-name>
<servlet>
<servlet-name>Faces Servlet</servlet-name>
<servlet-class>javax.faces.webapp.FacesServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>Faces Servlet</servlet-name>
<url-pattern>/faces/*</url-pattern>
</servlet-mapping>
<context-param>
<description>State saving method: 'client' or 'server' (=default). See JSF Specification 2.5.2</description>
<param-name>javax.faces.STATE_SAVING_METHOD</param-name>
<param-value>client</param-value>
</context-param>
<context-param>
<param-name>javax.servlet.jsp.jstl.fmt.localizationContext</param-name>
<param-value>resources.application</param-value>
</context-param>
<listener>
<listener-class>com.sun.faces.config.ConfigureListener</listener-class>
</listener>
<context-param>
<param-name>javax.faces.PROJECT_STAGE</param-name>
<param-value>Development</param-value>
</context-param>
<welcome-file-list>
<welcome-file>faces/index.xhtml</welcome-file>
</welcome-file-list>
<security-constraint>
<display-name>Tomcat7FormBasedJAAS</display-name>
<web-resource-collection>
<web-resource-name>secured</web-resource-name>
<description />
<url-pattern>/*</url-pattern>
</web-resource-collection>
<auth-constraint>
<description />
<role-name>user</role-name>
</auth-constraint>
</security-constraint>
<login-config>
<auth-method>FORM</auth-method>
<form-login-config>
<form-login-page>/faces/login.xhtml</form-login-page>
<form-error-page>/faces/error.xhtml</form-error-page>
</form-login-config>
</login-config>
<security-role>
<description />
<role-name>user</role-name>
</security-role>
</web-app>
server.xml(tomcat,片段)
<Realm className="org.apache.catalina.realm.JDBCRealm"
connectionName="database"
connectionPassword="password"
connectionURL="jdbc:mysql://localhost:3306/database"
driverName="com.mysql.jdbc.Driver"
roleNameCol="roleName"
userCredCol="password"
userNameCol="userName"
userRoleTable="user_role"
userTable="user"/>
【问题讨论】:
【参考方案1】:无论如何,我都不是该领域的专家,并且遇到了这个问题,因为我遇到了同样的问题。我最终做的是像这样在 web.xml 中有一个安全区域和一个非安全区域......
<security-constraint>
<web-resource-collection>
<web-resource-name>SecureArea</web-resource-name>
<url-pattern>/secure/*</url-pattern>
</web-resource-collection>
然后我有以下 URL 用于登录 /WAR/login.xhtml 对于我的应用程序的所有其余部分 /WAR/安全/*
这样就可以执行 loginBean。 像魅力一样工作。我不确定是否有更好的方法,但这对我有用。
【讨论】:
【参考方案2】:您的 login.xhtml 是安全区域,因此未经授权的用户不得访问任何 bean。
您可以像在自己的答案中那样继续,也可以定义一个“公共”区域, 让一切安全:
<security-constraint>
<web-resource-collection>
<web-resource-name>Public Area</web-resource-name>
<description>Public Area</description>
<url-pattern>/public/*</url-pattern>
</web-resource-collection>
</security-constraint>
现在您将 login.xhtml 移动到 public/login.xhtml 并更正 web.xml 中的登录配置:
<login-config>
<auth-method>FORM</auth-method>
<realm-name>ALMGCCAdminDB</realm-name>
<form-login-config>
<form-login-page>/public/login.xhtml</form-login-page>
<form-error-page>/public/error.xhtml</form-error-page>
</form-login-config>
</login-config>
【讨论】:
以上是关于基于 JSF 表单的身份验证 + 托管 Bean 登录不起作用的主要内容,如果未能解决你的问题,请参考以下文章
通过 JSF 表单成功登录后 Spring Security 不会重定向到登录页面
CAS认证后在JSF Managed Bean中获取LDAP属性
如何使用 Spring Security 3.1.3 和 JSF 创建一个 Bean 来验证我的登录表单