JSF基于表单的身份验证+托管Bean登录不起作用



我想实现一个托管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>

最新更新