2012-01-15 8 views
2

私はセッションリスナーを実装しました。私は、セッションが破棄された後にユーザーがサイトを使用しようとすると、ウェルカムページ(ログインページ)にリダイレクトする必要があります。 私はloging?faces-redirect=trueを実行してこれを試しましたが、実際にloginpageにリダイレクトされる前に2回クリックする必要があります。 さらに、ウェルカムページ(ログインページ)でセッションが終了したとき。次のエラーに示したように、アプリケーションのクラッシュ: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) 

私は、NetBeans おかげでprimefaces 3.0、GlassFishの3.1.1を使用しています。

+0

をweb.xmlに

<view-handler>PACKAGE.CustomViewHandler</view-handler> <--- CHANGE <lifecycle> <phase-listener>PACKAGE.AuthorizationListener</phase-listener> <--- CHANGE </lifecycle> 

追加私はあなたがあなたのセッションリスナー –

答えて

1

ユーザーが認証されていない場合は、サーブレット・フィルタまたはJSFフェーズ・リスナーを使用してログイン・ページにリダイレクトできます。

+0

JSFフェーズリスナーは、この中には非常に理想的なソリューションではありません私たちを見るべきだと思います場合。サーブレットフィルタを使用する必要があります。 – Apurv

0

私たちのアプリケーションでも同様の問題がありました。以下は、私たちが使い終わった解決策です。期限切れのセッションが発生した場合(ログインページにない場合)には、フェーズリスナーを使用してログインページにリダイレクトします。その後、カスタムビューハンドラを使用して、ログインページで期限切れのセッションが発生しないようにします。基本的に、セッションがログインページで期限切れになった場合は、新しいものを作成します。

注:特定のユースケースに合わせて更新する必要があるコードの部分には、マークが付けられています。 オンラインで見つかった特定の問題の例をいくつかまとめて、このアプローチを思いつきました。参考文献のいくつかは以下のとおりです。ここで

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

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

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

は、訪問者がセッションを持っていることを確認すると、彼らはドン場合は、ログインページに転送する責任相リスナーです1つを持っている(期限切れのときなど)。それはまた、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); 
    } 
} 

このコードを使用するには、設定ファイルの変更が必要です。顔-config.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> 
関連する問題