我曾在Openshift wildfly 8.1上托管了样本J2EE webapp,我收到了ViewExpiredException。之后,提供错误页面并重定向到此例外的登录页面。成功登录后,“登录”页面仍无法重定向到受保护的页面。
以下是使用(user1 / 1234)
登录的应用http://wildfly81-sysguard.rhcloud.com请在下面找到代码。
faces-config.xml中
<?xml version="1.0" encoding="UTF-8"?>
<faces-config
xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-facesconfig_2_0.xsd"
version="2.0">
<navigation-rule>
<display-name>Login.xhtml</display-name>
<from-view-id>/Login.xhtml</from-view-id>
<navigation-case>
<from-outcome>failure</from-outcome>
<to-view-id>/Login.xhtml</to-view-id>
<redirect />
</navigation-case>
</navigation-rule>
<factory>
<exception-handler-factory>org.omnifaces.exceptionhandler.FullAjaxExceptionHandlerFactory</exception-handler-factory>
</factory>
</faces-config>
的web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="3.0" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd">
<display-name>prime</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>*.xhtml</url-pattern>
</servlet-mapping>
<welcome-file-list>
<welcome-file>/Login.xhtml</welcome-file>
</welcome-file-list>
<security-constraint>
<display-name>User</display-name>
<web-resource-collection>
<web-resource-name>User Operations</web-resource-name>
<description/>
<url-pattern>/user/*</url-pattern>
</web-resource-collection>
<auth-constraint>
<description>User</description>
<role-name>Administrator</role-name>
<role-name>User</role-name>
</auth-constraint>
</security-constraint>
<login-config>
<auth-method>FORM</auth-method>
<realm-name>jdbc-security-domain</realm-name>
<form-login-config>
<form-login-page>/Login.xhtml</form-login-page>
<form-error-page>/Login.xhtml</form-error-page>
</form-login-config>
</login-config>
<security-role>
<role-name>Administrator</role-name>
</security-role>
<security-role>
<description/>
<role-name>User</role-name>
</security-role>
<error-page>
<exception-type>javax.faces.application.ViewExpiredException</exception-type>
<location>/Login.xhtml</location>
</error-page>
<mime-mapping>
<extension>woff</extension>
<mime-type>font/woff</mime-type>
</mime-mapping>
<mime-mapping>
<extension>ico</extension>
<mime-type>image/x-icon</mime-type>
</mime-mapping>
</web-app>
的JBoss-web.xml中
<?xml version="1.0" encoding="UTF-8"?>
<jboss-web>
<context-root>/</context-root>
<security-domain>java:/jaas/jdbc-security-domain</security-domain>
</jboss-web>
的pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>wildfly81</groupId>
<artifactId>wildfly81</artifactId>
<packaging>war</packaging>
<version>1.0</version>
<name>wildfly81</name>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>1.7</maven.compiler.source>
<maven.compiler.target>1.7</maven.compiler.target>
</properties>
<dependencies>
<dependency>
<groupId>org.primefaces</groupId>
<artifactId>primefaces</artifactId>
<version>5.0</version>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-entitymanager</artifactId>
<version>4.3.6.Final</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>javax</groupId>
<artifactId>javaee-api</artifactId>
<version>7.0</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.omnifaces</groupId>
<artifactId>omnifaces</artifactId>
<version>1.8.1</version>
</dependency>
</dependencies>
<profiles>
<profile>
<!-- When built in OpenShift the 'openshift' profile will be used when
invoking mvn. -->
<!-- Use this profile for any OpenShift specific customization your app
will need. -->
<!-- By default that is to put the resulting archive into the 'deployments'
folder. -->
<!-- http://maven.apache.org/guides/mini/guide-building-for-different-environments.html -->
<id>openshift</id>
<build>
<finalName>prime</finalName>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<version>2.3</version>
<configuration>
<failOnMissingWebXml>false</failOnMissingWebXml>
<outputDirectory>deployments</outputDirectory>
<warName>ROOT</warName>
</configuration>
</plugin>
</plugins>
</build>
</profile>
</profiles>
<repositories>
<repository>
<url>http://repository.primefaces.org/</url>
<id>PrimeFaces-maven-lib</id>
<layout>default</layout>
<name>Repository for library PrimeFaces-maven-lib</name>
</repository>
</repositories>
</project>
Login.xhtml
<ui:composition template="/templates/plain.xhtml"
xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:p="http://primefaces.org/ui">
<ui:define name="content">
<h:form id="loginForm">
<p:panelGrid columns="3">
<p:outputLabel for="username" value="Username" />
<p:inputText id="username" value="#{loginController.username}">
<f:validateLength minimum="1" />
</p:inputText>
<h:message class="error" for="username" />
<p:outputLabel for="password" value="Password" />
<p:password id="password" value="#{loginController.password}"
required="true">
<f:validateLength minimum="1" />
</p:password>
</p:panelGrid>
<h:message class="error" for="password" />
<p:commandButton styleClass="button" value="Login" update="@form"
actionListener="#{loginController.login}" type="submit" />
</h:form>
</ui:define>
</ui:composition>
LoginPageFilter.java
package com.prime.filter;
import java.io.IOException;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.faces.application.ResourceHandler;
import javax.inject.Inject;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* To prevent user from going back to Login page if the user already logged in
*
* @author prime
*/
@WebFilter(urlPatterns="/Login.xhtml")
public class LoginPageFilter implements Filter {
@Inject
private transient Logger logger;
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) servletRequest;
HttpServletResponse response = (HttpServletResponse) servletResponse;
if (request.getUserPrincipal() != null) { //If user is already authenticated
String navigateString = "/user/expirepage.xhtml";
String url = request.getContextPath() + navigateString;
response.sendRedirect(url);
logger.log(Level.INFO, "Redirect to {0}",url);
} else {
if (!request.getRequestURI().startsWith(request.getContextPath() + ResourceHandler.RESOURCE_IDENTIFIER)) {
response.setHeader("Cache-Control", "no-cache, no-store, must-revalidate");
response.setHeader("Pragma", "no-cache");
response.setDateHeader("Expires", 0);
logger.log(Level.INFO, "Clear Cache {0}",response.toString());
}
filterChain.doFilter(servletRequest, response);
}
}
@Override
public void destroy() {
}
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
}
LoginController.java
package com.prime.controller;
import java.io.IOException;
import java.io.Serializable;
import java.security.MessageDigest;
import java.security.Principal;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.enterprise.context.SessionScoped;
import javax.faces.context.FacesContext;
import javax.faces.event.ActionEvent;
import javax.inject.Inject;
import javax.inject.Named;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import javax.validation.constraints.NotNull;
import com.prime.util.DateUtility;
/**
* Login Controller class allows only authenticated users to log in to the web
* application.
*
* @author prime
*/
@Named
@SessionScoped
public class LoginController implements Serializable {
private static final long serialVersionUID = 1L;
@Inject
private transient Logger logger;
@Inject
FacesContext facesContext;
@NotNull
private String username;
@NotNull
private String password;
private String email;
/**
* Creates a new instance of LoginController
*/
public LoginController() {
}
// Getters and Setters
/**
* @return username
*/
public String getUsername() {
return username;
}
/**
*
* @param username
*/
public void setUsername(String username) {
this.username = username;
}
/**
*
* @return password
*/
public String getPassword() {
return password;
}
/**
*
* @param password
*/
public void setPassword(String password) {
this.password = password;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
/**
* Listen for button clicks on the #{loginController.login} action,
* validates the username and password entered by the user and navigates to
* the appropriate page.
*
* @param actionEvent
*/
public void login(ActionEvent actionEvent) {
HttpServletRequest request = (HttpServletRequest) facesContext.getExternalContext().getRequest();
try {
try{
MessageDigest md = java.security.MessageDigest.getInstance("MD5");
md.update(password.getBytes("UTF-8"));
byte[] passwordDigest = md.digest();
@SuppressWarnings("restriction")
String encodedPasswordHash = new sun.misc.BASE64Encoder().encode(passwordDigest);
logger.log(Level.INFO, "Encripted Password {0}" ,encodedPasswordHash);
} catch(Exception e){
e.printStackTrace();
}
// Checks if username and password are valid if not throws a ServletException
request.login(username, password);
// gets the user principle and navigates to the appropriate page
Principal principal = request.getUserPrincipal();
String navigateString = "/user/expirepage.xhtml";
try {
logger.log(Level.INFO, "User ({0}) loging in #" + DateUtility.getCurrentDateTime(), request.getUserPrincipal().getName());
facesContext.getExternalContext().redirect(request.getContextPath() + navigateString);
} catch (IOException ex) {
logger.log(Level.SEVERE, "IOException, Login Controller" + "Username : " + principal.getName(), ex);
}
} catch (ServletException e) {
logger.log(Level.SEVERE, "Login Controller: The username or password you provided does not match our records.");
facesContext.validationFailed();
}
}
/**
* Listen for logout button clicks on the #{loginController.logout} action
* and navigates to login screen.
*/
public void logout(ActionEvent actionEvent) {
HttpSession session = (HttpSession) facesContext.getExternalContext().getSession(false);
HttpServletRequest request = (HttpServletRequest) facesContext.getExternalContext().getRequest();
logger.log(Level.INFO, "User ({0}) loging out #" + DateUtility.getCurrentDateTime(), request.getUserPrincipal().getName());
if (session != null) {
session.invalidate();
}
facesContext.getApplication().getNavigationHandler().handleNavigation(facesContext, null, "/Login.xhtml?faces-redirect=true");
}
}
答案 0 :(得分:0)
<context-root>/</context-root>
以上导致问题。如果将上下文根更改为任何其他,例如:
,则没有问题<context-root>/noproblem</context-root>
我认为自WildFly 8.0 RC1发布以来就出现了一个错误。在WildFly 8.0 Beta1和JBoss 7上都可以。
如果上下文根是“/”,则服务器会为每个浏览器窗口创建多个会话。然后每个子上下文/子文件夹都有自己的会话。这会导致你的问题。
我是在本地机器上观察到的,而不是在云端。
答案 1 :(得分:0)
问题是由于多个JSessionid导致根上下文为&#34; /&#34;。我通过在jboss-web.xml
添加以下配置修复了该问题<?xml version="1.0"?>
<jboss-web>
<session-config>
<cookie-config>
<path>/</path>
</cookie-config>
</session-config>
</jboss-web>
<xml>