2012-01-15 73 views
2

我已經實現了會話偵聽器。我希望當用戶在會話被銷燬後嘗試使用該站點時,他應該被重定向到歡迎頁面(登錄頁面)。 我已經通過做loging?faces-redirect=true試過了,但我必須點擊兩次,才能真正將其重定向到登錄頁面。 此外,當在歡迎頁面(登錄頁面)上會話過期時。如下面的錯誤中所示的應用程序崩潰:返回歡迎頁面在jsf中銷燬的會話

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) 

我使用primefaces 3.0,上的netbeans的glassfish 3.1.1 感謝。

+0

我覺得你應該告訴我們你的會話監聽 – 2012-01-15 09:31:04

回答

1

如果用戶未通過身份驗證,則可以使用servlet篩選器或JSF階段偵聽器重定向到登錄頁面。

+0

JSF phase監聽器是不是這是一個非常理想的解決方案案件。應該使用Servlet過濾器。 – Apurv 2012-01-15 17:58:45

0

我們在應用程序中遇到了類似的問題。以下是我們最終使用的解決方案。如果會話過期,我們使用階段偵聽器重定向到登錄頁面(並且它們不在登錄頁面上)。然後,我們使用自定義視圖處理程序來防止用戶在登錄頁面上遇到過期的會話。基本上,如果我們在登錄頁面上看到會話已過期,我們會創建一個新會話。

注意:需要爲特定用例更新的部分代碼被標記。 我們想出了這種方法,爲我們在網上找到的具體問題彙集了幾個例子。有些引用是:

http://www.gregbugaj.com/?p=164

https://stackoverflow.com/a/6816513/2212458

https://stackoverflow.com/a/4992869/2212458

這裏是相聽衆負責確保訪問者都有一個會話,並將其轉發到登錄頁面,如果他們不沒有一個(例如它已經過期)。它還執行2個其他檢查。它可以確保他們是否有會話,是否進行了身份驗證(登錄),並確保他們有權訪問他們正在訪問的頁面。

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>