我已经实现了一个会话监听器。我希望当用户在会话被销毁后尝试使用该网站时,他应该被重定向到欢迎页面(登录页面)。
我已经通过loging?faces-redirect=true
尝试了这个,但我必须先点击两次才能真正重定向到登录页面。
此外,当会话在欢迎页面(登录页面)上到期时。应用程序崩溃,如以下错误所示:
WARNING: StandardWrapperValve[Faces Servlet]: PWC1406: Servlet.service() for servlet Faces Servlet threw exception
javax.faces.application.ViewExpiredException: viewId:/loginpage.xhtml - View /loginpage.xhtml could not be restored.
at com.sun.faces.lifecycle.RestoreViewPhase.execute(RestoreViewPhase.java:205)
at com.sun.faces.lifecycle.Phase.doPhase(Phase.java:101)
at com.sun.faces.lifecycle.RestoreViewPhase.doPhase(RestoreViewPhase.java:116)
at com.sun.faces.lifecycle.LifecycleImpl.execute(LifecycleImpl.java:118)
at javax.faces.webapp.FacesServlet.service(FacesServlet.java:593)
at org.apache.catalina.core.StandardWrapper.service(StandardWrapper.java:1539)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:281)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:175)
at org.apache.catalina.core.StandardPipeline.doInvoke(StandardPipeline.java:655)
at org.apache.catalina.core.StandardPipeline.invoke(StandardPipeline.java:595)
at com.sun.enterprise.web.WebPipeline.invoke(WebPipeline.java:98)
at com.sun.enterprise.web.PESessionLockingStandardPipeline.invoke(PESessionLockingStandardPipeline.java:91)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:162)
at org.apache.catalina.connector.CoyoteAdapter.doService(CoyoteAdapter.java:330)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:231)
at com.sun.enterprise.v3.services.impl.ContainerMapper.service(ContainerMapper.java:174)
at com.sun.grizzly.http.ProcessorTask.invokeAdapter(ProcessorTask.java:828)
at com.sun.grizzly.http.ProcessorTask.doProcess(ProcessorTask.java:725)
at com.sun.grizzly.http.ProcessorTask.process(ProcessorTask.java:1019)
at com.sun.grizzly.http.DefaultProtocolFilter.execute(DefaultProtocolFilter.java:225)
at com.sun.grizzly.DefaultProtocolChain.executeProtocolFilter(DefaultProtocolChain.java:137)
at com.sun.grizzly.DefaultProtocolChain.execute(DefaultProtocolChain.java:104)
at com.sun.grizzly.DefaultProtocolChain.execute(DefaultProtocolChain.java:90)
at com.sun.grizzly.http.HttpProtocolChain.execute(HttpProtocolChain.java:79)
at com.sun.grizzly.ProtocolChainContextTask.doCall(ProtocolChainContextTask.java:54)
at com.sun.grizzly.SelectionKeyContextTask.call(SelectionKeyContextTask.java:59)
at com.sun.grizzly.ContextTask.run(ContextTask.java:71)
at com.sun.grizzly.util.AbstractThreadPool$Worker.doWork(AbstractThreadPool.java:532)
at com.sun.grizzly.util.AbstractThreadPool$Worker.run(AbstractThreadPool.java:513)
at java.lang.Thread.run(Thread.java:662)
我在netbeans上使用primefaces 3.0,glassfish 3.1.1 感谢。
答案 0 :(得分:1)
如果用户未经过身份验证,您可以使用servlet过滤器或JSF阶段侦听器重定向到登录页面。
答案 1 :(得分:0)
我们的申请中也有类似的问题。以下是我们最终使用的解决方案。我们使用阶段监听器在会话过期时重定向到登录页面(并且它们不在登录页面上)。然后,我们使用自定义视图处理程序来防止用户在登录页面上遇到过期的会话。基本上,如果我们在登录页面上看到会话已过期,我们会创建一个新会话。
注意:标记了需要针对特定用例更新的部分代码。 我们通过汇总我们在网上发现的具体问题的几个例子,提出了这种方法。一些参考文献是:
http://www.gregbugaj.com/?p=164
https://stackoverflow.com/a/6816513/2212458
https://stackoverflow.com/a/4992869/2212458
这是阶段监听器,负责确保访问者有会话并将其转发到登录页面,如果他们没有会话(例如它已过期)。它还执行另外两项检查。它确保他们有一个会话,他们是经过身份验证(登录),并确保他们有权访问他们正在访问的页面。
import javax.faces.application.NavigationHandler;
import javax.faces.context.FacesContext;
import javax.faces.event.*;
import javax.servlet.http.HttpSession;
/**
* A phase listener. Runs after the restore view phase. Makes sure that the user is logged on
* to view any page other than the login page.
*/
public class AuthorizationListener implements PhaseListener
{
/**
* Called after phase executes. Makes sure we are logged in if we are not on the login page.
* @param phaseEvent
*/
@Override
public void afterPhase(PhaseEvent phaseEvent)
{
// get page we are on
FacesContext facesContext = phaseEvent.getFacesContext();
String currentPage = facesContext.getViewRoot().getViewId();
// determine if we are on the login page
boolean isLoginPage = currentPage.contains("login"); <--- CHANGE
if (isLoginPage)
{
return;
}
// get session - do not create one if it does not exist
HttpSession session = (HttpSession) facesContext.getExternalContext().getSession(false);
// no session is present
if(session==null)
{
NavigationHandler nh = facesContext.getApplication().getNavigationHandler();
nh.handleNavigation(facesContext, null, "login?faces-redirect=true&reason=expired"); <--- CHANGE
return;
}
// if not logged in send to login page
if (USER IS NOT LOGGED IN) <--- CHANGE
{
NavigationHandler nh = facesContext.getApplication().getNavigationHandler();
nh.handleNavigation(facesContext, null, "login?faces-redirect=true&reason=expired"); <--- CHANGE
return;
}
// they are logged in, make sure they have rights to page they are visiting
if (USE DOES NOT HAVE RIGHTS TO THE PAGE THEY ARE VISITING) <--- CHANGE
{
// user does not have privilege to go to this page
NavigationHandler nh = facesContext.getApplication().getNavigationHandler();
nh.handleNavigation(facesContext, null, accessDenied); <--- CHANGE
}
}
/**
* Called before phase executes. Does nothing.
* @param phaseEvent the phase event
*/
@Override
public void beforePhase(PhaseEvent phaseEvent)
{
// intentionally left blank
}
/**
* Identifies the phase we want to listen and respond to.
* @return the phase
*/
@Override
public PhaseId getPhaseId()
{
return PhaseId.RESTORE_VIEW;
}
}
以下是负责在登录页面上停止会话过期的自定义视图处理程序。
import javax.faces.application.ViewHandler;
import javax.faces.application.ViewHandlerWrapper;
import javax.faces.component.UIViewRoot;
import javax.faces.context.FacesContext;
import java.io.IOException;
/**
* This class adds additional behavior to the facelet view handler. Specifically it
* prevents the user from experiencing session/view timeout errors at the login screen.
*/
public class CustomViewHandler extends ViewHandlerWrapper
{
/** The default view handler we are adding extra behavior to. */
private ViewHandler wrapped;
/**
* Constructor.
* @param wrapped the wrapped handler. Ref.
*/
public CustomViewHandler(ViewHandler wrapped)
{
super();
this.wrapped = wrapped;
}
/**
* Expose the wrapped handler (required by base class).
* @return the handler. Ref.
*/
@Override
public ViewHandler getWrapped()
{
return wrapped;
}
/**
* Called when a view is restored. Prevents expiration on login page.
* @param facesContext the context for this request
* @param viewId the view identifier for the current request
* @return the restored view
*/
@Override
public UIViewRoot restoreView(FacesContext facesContext, String viewId)
{
// have the wrapped handler restore the view
UIViewRoot root = super.restoreView(facesContext, viewId);
// if there was no view to restore (maybe because it expired)
if (root == null)
{
// if the view expired on the login page make a new view, don't allow login page to expire
if ( viewId.contains("login") ) <--- CHANGE
{
// create a new view
// for some reason the starting slash is required else we get errors in server log about not finding the page
root = createView(facesContext, "/" + "login"); <--- CHANGE
// saves view - without this session never gets created so we will just keep hitting this code
facesContext.renderResponse();
}
}
return root;
}
/**
* Called when a view is rendered. Does nothing but log a message.
* @param context the context for this request
* @param viewToRender the view to render
* @throws IOException thrown if an input/output error occurs in wrapped handler
*/
@Override
public void renderView(FacesContext context, UIViewRoot viewToRender) throws IOException
{
super.renderView(context, viewToRender);
}
}
使用此代码需要更改配置文件。
添加到faces-config.xml
<view-handler>PACKAGE.CustomViewHandler</view-handler> <--- CHANGE
<lifecycle>
<phase-listener>PACKAGE.AuthorizationListener</phase-listener> <--- CHANGE
</lifecycle>
添加到web.xml
<error-page>
<exception-type>javax.faces.application.ViewExpiredException</exception-type>
<location>/login.xhtml?reason=expired</location> <--- CHANGE
</error-page>-<session-config><session-timeout> 10 </session-timeout></session-config>
<listener><listener-class> com.sun.faces.config.ConfigureListener </listener-class></listener>