我想实现一个托管Bean Form Base身份验证,遵循Java EE 6 Turorial我配置并构建了所有必需的元素,如登录表单、错误页面、web.xml安全配置和Tomcat安全领域(JDBC)。
问题出在哪里本应调用托管Bean中的login()方法的commandButton不起作用,我可以看到构造函数和getter被调用,但login方法和setter不起作用。
好奇的是什么如果我从web.xml中删除了所有与安全相关的元素,请重新启动应用程序并直接转到login.xhtml表单,login()方法确实会被调用。
结论如果使用托管bean,那么JSF实现中一定有某种东西阻止了这种基于表单的身份验证正常工作。
注意:常规的j_security_check基于表单的身份验证(不使用JSF)运行良好。
有什么想法吗
登录.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,fragment)
<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"/>
我无论如何都不是这方面的专家,我遇到了同样的问题。我最终做的是在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。工作起来很有魅力。我不确定是否有更好的方法,但这对我有效。
您的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>