1

私は Glassfish [GlassFish Server Open Source Edition 3.1.2.2 (build 5);] で JSF アプリケーションを実行しています。モハラ 2.1.6 (スナップショット 20111206)]。PrimeFaces 3.5 と OmniFaces バージョン 1.5 を使用しています。フォームベースのログイン認証を使用しています

<login-config>
    <auth-method>FORM</auth-method>
    <realm-name>reportingRealm</realm-name>
    <form-login-config>
        <form-login-page>/faces/login.xhtml</form-login-page>
        <form-error-page>/loginError.xhtml</form-error-page>
    </form-login-config>
</login-config>

web.xml でエラー ページを定義している

<error-page>
  <exception-type>java.lang.Throwable</exception-type>
  <location>/faces/viewExpired.xhtml</location>
</error-page>

サーブレット マッピング用の次の URL パターンがあります (関連する場合)。

<servlet-mapping>
    <servlet-name>Faces Servlet</servlet-name>
    <url-pattern>/faces/*</url-pattern>
</servlet-mapping>

アプリケーションはもともと AJAX を使用していませんでした。具体的には、AJAX を使用しない ap:commandButton がありました。セッションが期限切れになり、このボタンがクリックされた場合、例外処理は次のように進行します。ログイン ページが表示されました。ログイン資格情報を (再) 入力してログインすると、セッション期限切れのページが表示されました。再度ログインすることを選択すると、ビジネスに戻ります。私はこれで何の問題もありません。(元々、エラーページで ViewExpiredException を具体的に参照したと信じていることに注意してください。現在構成されているため、Throwable ではありません。私が説明する動作は、Throwable が使用されている場合と ViewExpiredException が使用されている場合の両方で発生します。 ViewExpiredException の場合 OmniFaces の要件を満たすために例外タイプを追加しました)。

p:commandButton がクリックされたときに AJAX を使用するようにアプリケーションを変更しました。これをサポートするために、OmniFaces (私が強くお勧めするソリューション) をプロジェクトに追加し、form-login-page を「/login.xhtml」から「/faces/login.xhtml」に変更しました (OmniFaces を理解しているため)。ドキュメンテーション、および私の構成を考えると、これは必要です; 実際、form-login-page が '/login.xhmtl' に等しい場合、AJAX が有効でないコントロールを使用する場合、例外処理は以前と同じように機能し続けましたが、何も起こりませんでしたAJAX 対応のコントロールをクリックしたとき (表示されたページに変更はなく、何もログに記録されません)。

AJAX を使用する p:commandButton、OmniFaces を使用し、form-login-page を「/faces/login.xhtml」に変更すると、セッションが期限切れになり、AJAX 対応のコントロールをクリックすると、ViewExpiredException 処理が完全に機能します (実際、ViewExpiredException が非 AJAX 対応コントロールに対して処理されるときに発生するシーケンスよりも発生するシーケンスを好みます: OmniFaces を使用したシーケンスでは、セッション期限切れのページに直接移動します。仕事。)

ただし、現在、セッションの有効期限が切れて、AJAX が有効になっていないコントロールをクリックすると、ブラウザー ウィンドウに (現在表示されているページの唯一のコンテンツとして) 以下が表示されます。

XML Parsing Error: no element found
Location: http://localhost:8080/Reporting-war/faces/protected/multiUser.xhtml
Line Number 1, Column 1;

以下が記録されます。

WARNING: ApplicationDispatcher[/Reporting-war] PWC1231: Servlet.service() for servlet Faces Servlet threw exception
javax.faces.application.ViewExpiredException: viewId:/login.xhtml - View /login.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 java.lang.Thread.run(Thread.java:722)

WARNING: Unexpected error forwarding or redirecting to login page
javax.servlet.ServletException: viewId:/login.xhtml - View /login.xhtml could not be restored.
    at javax.faces.webapp.FacesServlet.service(FacesServlet.java:606)
    at org.apache.catalina.core.StandardWrapper.service(StandardWrapper.java:1550)
...
    at java.lang.Thread.run(Thread.java:722)
Caused by: javax.faces.application.ViewExpiredException: viewId:/login.xhtml - View /login.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 javax.faces.webapp.FacesServlet.service(FacesServlet.java:593)
    ... 32 more

form-login-page の値が「/faces/login.xhtml」の場合、OmniFaces が使用されているかどうかに関係なくエラーが発生することに注意してください。これが OmniFaces の問題だとは思いません。ただし、(a)なぜそれが起こっているのか、または(b)既存の構成を維持し(たとえば、サーブレットマッピングを維持するなど)、セッションの期限切れ処理を機能させる方法があるかどうかを理解していません。 AJAX 対応のコントロールと非 AJAX 対応のコントロールの両方。

multiUser.xhtml は次のように始まります。

<?xml version='1.0' encoding='UTF-8' ?>
<!DOCTYPE composition PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<ui:composition xmlns:ui="http://java.sun.com/jsf/facelets"
                template="./mainTemplate.xhtml"
                xmlns:p="http://primefaces.org/ui"
                xmlns:h="http://java.sun.com/jsf/html"
                xmlns:c="http://java.sun.com/jsp/jstl/core"
                xmlns:f="http://java.sun.com/jsf/core"
                xmlns="http://www.w3.org/1999/xhtml">

    <ui:define name="top">
    </ui:define>

<ui:define name="content">
...

login.xhtm の全体は次のとおりです。

<?xml version="1.0" encoding="UTF-8"?>
<!--
To change this template, choose Tools | Templates
and open the template in the editor.
-->
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
    <head>
        <title>Login</title>
    </head>
    <body>
        <form method="POST" action="j_security_check">
            Username
            <input type="text" name="j_username"/>
            Password
            <input type="password" name="j_password"/>
            <input type="submit" value="Login"/>
        </form>
    </body>
</html>

viewExpired.xhtml の全体は次のとおりです。

<?xml version="1.0" encoding="UTF-8"?>
<!--
To change this template, choose Tools | Templates
and open the template in the editor.
-->
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
      xmlns:h="http://java.sun.com/jsf/html">
    <head>
        <title>Expired Session</title>
    </head>
    <body>
        <div>
            <p>
                Your login session has expired.
            </p>
            <p>
                <h:form>
                    <h:link value="Login Again" outcome="home"/>
                </h:form>
            </p>
        </div>
    </body>
</html>

なぜこれが起こっているのかを理解し、それに対処するためのオプションが何であるかを理解して、誰でもできる助けをいただければ幸いです。ありがとう。

4

1 に答える 1

1

具体的な問題は、平均的なコンテナがデフォルトで FORM ベースの認証にヒットした POST リクエストの POST データを保存するために発生します。この POST データ (すべての POST 要求パラメーター) は、FORM ベースの認証が成功したときに復元されます。JSFjavax.faces.ViewState隠しフィールドの値は、POST データにも存在します。

FORM ベースの認証は POST によって実行され、javax.faces.ViewState非表示のフィールド値がリクエスト パラメータ マップに存在するため、 がFacesContext#isPostback()trueRestoreViewPhase#execute()と評価されるため、JSF は新しいビューを作成する代わりにビューを実際に復元しようとします。ただし、javax.faces.ViewState隠しフィールドは実際には、現在のセッションにはもう存在しない、前のセッションの古いビュー ステートを参照しているため、 aViewExpiredExceptionがスローされます。

これは残念な問題です。基本的に、Servlet API と JSF API は衝突しています。基本的に2つの解決策があります:

  1. FORM ベースの認証用に POST データを保存しないようにコンテナーに指示します。Tomcat とクローンの場合、要素のmaxSavePostSize属性をに設定するだけです。<Connector>/conf/server.xml-1

    <Connector ... maxSavePostSize="-1">
    

    Glassfish 3.x の場合、申し訳ありませんがわかりません! 私はそのドキュメントをざっと見ましたが、すぐに近いものは何も見つかりません。

  2. 使用しないでくださいj_security_check。真の JSF フォームと真のバッキング Bean を使用して、代わりにプログラムによる認証を使用してください。これにより、成功したログインの処理をよりきめ細かく制御できます。精巧なコード スニペットについては、「更新」で始まるこの回答の後半を確認してください: j_security_check を使用して Java EE / JSF でユーザー認証を実行しています。リクエスト URI。

ログインページは OmniFaces の ajax レスポンスによって指示されたリダイレクトによって開かれるため、ajax リクエストに対して機能します。そのため、FORM ベースの認証チェックにヒットした時点では、基本的に POST データを保存する必要はありません。

于 2013-11-06T21:02:00.607 に答える