Oracle WebCenter Framework WebCenterアプリケーションの構築 - ステップ・バイ・ステップ 10g(10.1.3.2.0) E05617-02 |
|
この章では、ユーザーが認証のためにリダイレクトされるログイン・ページを新規作成します。通常、WebCenterアプリケーションにはパブリック・ページの概念があり、明示的な認証も暗黙的な認証も可能です。つまり、ユーザーは、ログイン・リンクをクリックしてアプリケーションにログインしてから保護コンテンツに移動する(明示的)、あるいは保護ページに移動するとアプリケーションのログイン・ページにリダイレクトされる(暗黙的)ことが可能です。暗黙的および明示的な認証の詳細は、『Oracle WebCenter Framework開発者ガイド』の「WebCenterアプリケーションの保護」を参照してください。図6-1に、この章で構築するサンプルのログイン・ページを示します。
SRDemoSample_Starter
アプリケーションには、すでにログイン・ページSRLogin.jspx
が含まれています。このページは、図6-2に示す場所にあります。
ログイン・ページではログイン・フォームを使用するので、通常、ADF Facesページはログイン・ページに使用しません。これは、ADF Facesライフサイクルがログイン・フォームの送信アクションおよびフォームのフィールドを内部参照に再マップして、ログイン機能を中断するためです。しかし、ログイン・ページはアプリケーションの重要な部分です。このページには、ポートレットやデータ・コントロールなどのカスタマイズ可能な情報を含めることができます。また、ADF Facesページで使用できるスキニング機能を利用することも可能です。また、ログイン・ポートレットを実装してもかまいません。この章では、SRDemoアプリケーション用にADF Facesベースのログイン・ページを構築する方法について学びます。このログイン・ページのフォームでは、J2EEセキュリティ・コンテナ・ログイン・メソッドj_security_check
も使用します。この章の内容は次のとおりです。
ADF Facesベースのログイン・ページを作成するには、次の手順を実行します。
SRLoginADF.jspx
と入力します。
SRLoginADF.jspx
ページの「ソース」ビューで、例6-1に示すコードをコピーし、f:view
タグの直前に貼り付けます。<!-- Resource Bundle for Translatable Strings within Application =========== --> <f:loadBundle basename="oracle.srdemo.view.resources.UIResources" var="res"/>
body
要素の上にドラッグします。要求されても、フォームを追加しないでください。これは、後で独自のフォームを追加してデフォルトのフォーム要素を削除するためです。
Title
プロパティを変更し、アプリケーションに付属するリソース・バンドルの文字列にバインドします。プロパティ・インスペクタで、「Title」をクリックします。
srlogin.pageTitle
変数を探します。
srlogin.pageTitle
にファセットをいくつか追加します。そのためには、例6-2に示す既存のブランド・ファセット・コードを探します。<f:facet name="branding"/>
<!-- Site Branding Section (Top Left of Page) ============================== --> <f:facet name="branding"> <af:objectImage source="/skins/#{skinBean.currentSkin}/skin_images/SRBranding.gif"/> </f:facet>
SRLoginADF.jspx
ページで、例6-4に示す既存のコピーライト・ファセット・コードを探します。 <f:facet name="appCopyright"/>
<!-- Copyright Message --> <f:facet name="appCopyright"> <h:panelGroup> <af:outputText value="#{res['srdemo.copyright']}"/> <af:objectSpacer width="10" height="10"/> </h:panelGroup> </f:facet>
「backing」
→「infrastructure」
フォルダ内にあるバッキングBeanのSRLoginADF.java
(図6-3を参照)を開き、HTML挿入コードをバッキングBeanに追加して実行時にページに挿入されるようにします。このコードは原則として、該当するHTMLをページに直接生成します。そのため、様々なgetterメソッドが適切にマークアップされたHTMLを単純な文字列として返します。この動的に生成されたHTMLを使用するメリットは、スキン情報への参照を組み込むことができることです。FacesページへのHTMLの統合は、ページ内のタグおよびCDATAエスケープをそのまま使用しないことで簡略化されます。import javax.faces.application.FacesMessage; import javax.faces.context.FacesContext; import javax.servlet.http.HttpSession; import oracle.adf.share.ADFContext; import oracle.adf.view.faces.component.core.output.CoreMessages; import oracle.srdemo.view.util.JSFUtils;
SRLoginADF.java
の先頭に追加します(例6-7を参照)。これらのプロパティのgetterメソッドは、後でログイン・ページの式言語で参照されます。private String _loginStyleBlock = null; private String _loginScriptBlock = null; private String _loginFormBlock = null; private boolean _validLoginAttempt = true;
表6-1に、これらのプロパティの説明を示します。
getloginStyleBlock
getterメソッドをバッキングBeanに挿入します。例6-8を参照してください。このメソッドは、認証プロセスが実行中であることを示すために、ログイン・フォームで使用されるフラッシュ・テキストを定義する単純なスタイルシートを生成します。このメソッドによって生成されるHTMLは表示できないため、ページの本体の外側に出力文字列をレンダリングできます。
/** * ============================================================================ * Function to generate the CSS style class referenced in Login Form * ============================================================================ * @return */ public String getloginStyleBlock() { _loginStyleBlock = "\n\n" + "<!-- ========= CSS Style Block Generated in Backing Bean ========= -->\n" + "<style type=\"text/css\">\n" + ".VP_Blink {text-decoration: blink;}\n" + "</style>\n" + "<!-- ============================================================= -->" + "\n\n"; return (_loginStyleBlock); }
getloginScriptBlock
getterメソッドをバッキングBeanに挿入します。例6-9を参照してください。このメソッドは、ログイン・フォームで使用されるJavaScript関数を含む<script>
ブロックを生成します。これらの関数には、フィールド検証アクションやフォーム送信アクションがあります。JavaScriptは動的に生成されるため、現行スキンへの参照の他にリソース・バンドルの適切な文字列を組み込むことができます。たとえば、現行スキンがmyCompany
に設定されている場合、次の行は、JavaScriptのアラート・メッセージをリソース・バンドル・キーに定義されている値(SRLoginADF.myCompany.jsAlert
)になるように設定します。
String alertMsg = JSFUtils.getStringFromBundle("SRLoginADF." + currentSkin + ".jsAlert");
同様に、このメソッドは、認証中であることを示す適切なアイコンを特定し、Faces外部コンテキストに基づいてそのアイコンへのURLを生成します。
/** * ============================================================================ * Method getloginScriptBlock() to generate a JScript Submit form block. * This function implements the current skin and generates simple JavaScript * to validation the user input prior to the Authentication submit action. * ============================================================================ * @return */ public String getloginScriptBlock() { String currentSkin = (String) JSFUtils.getManagedBeanValue("skinBean.currentSkin"); String alertMsg = JSFUtils.getStringFromBundle("SRLoginADF." + currentSkin + ".jsAlert"); String valPwdMsg = JSFUtils.getStringFromBundle("SRLoginADF." + currentSkin + ".AuthMsg"); String urlBaseRef = FacesContext.getCurrentInstance().getCurrentInstance().getExternalContext().getRequestC ontextPath(); String processIcon = urlBaseRef + "/skins/" + currentSkin + "/skin_images/process_animation.gif"; _loginScriptBlock = "\n\n" + "<!-- ======== JavaScript Block Generated in Backing Bean ========= -->\n" + "<SCRIPT language=\"JavaScript\" type=\"text/JavaScript\">\n" + "(new Image(32,32)).src=\"" + processIcon +"\";\n" + "function SubmitForm(AuthFrm){\n" + "var alertMsg =\"" + alertMsg + "\";\n" + "var valPwdMsg = \"" + valPwdMsg + "\";\n\n" + "if (((AuthFrm.j_username.value == null) || (AuthFrm.j_username.value ==\"\")) ||\n" + " ((AuthFrm.j_password.value == null) || (AuthFrm.j_password.value ==\"\")))\n" + " {\n alert(alertMsg);\n return false;\n }\n else\n {\n" + " var divTag = document.getElementById(\"vp\");\n" + " divTag.innerHTML = '<table width=\"50\" border=\"0\"><tr>' +\n" + " '<td align=\"center\"><img src=\"" + processIcon + "\" width=\"32\" height=\"32\"></td>' +\n" + " '<td align=\"left\"><font size=\"-2\" class=\"VP_Blink\">' + valPwdMsg + '</font></td>' +\n" + " '</tr></table>';\n" + " return true;\n" + " }\n}\n" + "</SCRIPT>\n" + "<!-- ============================================================= -->" + "\n\n"; return (_loginScriptBlock); }
getLoginFormBlock
getterメソッドをバッキングBeanに挿入します。例6-10を参照してください。このメソッドは、ページ内にレンダリングされるHTMLログイン・フォームを定義する文字列を生成します。HTMLは動的であるため、現行スキンへの参照の他にリソース・バンドルのキーも組み込むことができます。さらに、ログイン・ページはログイン後にカスタマイズできるように設計されているため、ADFセキュリティ・コンテキストのisAuthenticated();
メソッドを使用してHTMLのdisabledプロパティが動的に設定されるので、HTMLはユーザーの認証状態を敏感に反映します。
その場合、ユーザーが認証されてログイン・ページがアクセスされると、ログイン・ページは(レンダリング時に)非アクティブ化されてそれ以降のログイン試行はできなくなります。たとえば、サイト管理ページからページがアクセスされる場合
(第9章「サイト管理ページの構築」を参照)がこれに該当します。
次の例では、ADFセキュリティ・コンテキストのisAuthenticated
の状態に基づいて、文字列変数htmlDisable
が"disabled="true""
またはnull
のいずれかになることがわかります。
String htmlDisable =(ADFContext.getCurrent().getSecurityContext().isAuthenticated() ? "disabled=\"true\"" : null);
次のコードは、その後で、入力フィールドや「送信」ボタンなどのフォーム要素をアクティブ化または無効化するために、htmlDisable
文字列を使用する方法を示しています。
<input type=\"text\" name=\"j_username\" "+ htmlDisable + "/></td>\n"例6-10 getLoginFormBlock getterメソッド
/** * =========================================================================== * Method getLoginFormBlock() generates the standard Credential Form used * by container security. The function implements the current skin values and * returns the required HTML which is subsequently output using an OutputText * object populated using EL. While this could also have been achieved by * directly using the Verbatim tags within the JSPX itself, this would require the * use of CDATA escapes and complicates the design of the page (the login form * is exposed through a faces component in this case.) * * Note as the Login Page contains customizable components, the HTML form elements * generated are disabled if the user is currently authenticated. * ========================================================================== * @return */ public String getLoginFormBlock() { String currentSkin = (String) JSFUtils.getManagedBeanValue("skinBean.currentSkin"); String userNameLabel = JSFUtils.getStringFromBundle("SRLoginADF." + currentSkin + ".userName"); String passwordLabel = JSFUtils.getStringFromBundle("SRLoginADF." + currentSkin + ".password"); String submitButtonLabel = JSFUtils.getStringFromBundle("SRLoginADF." + currentSkin + ".buttonLabel"); String htmlDisable = (ADFContext.getCurrent().getSecurityContext().isAuthenticated() ? "disabled=\"true\"" : null); _loginFormBlock = "\n\n" + "<!-- ======== Login Form Block Generated in Backing Bean ========= -->\n" + "<form name=\"LoginForm\" id=\"LoginForm\" \n" + " action=\"j_security_check\" method=\"POST\" onSubmit=\"return SubmitForm(this)\" >\n" + "<table cellspacing=\"5\" cellpadding=\"0\" border=\"0\" width=\"50%\" bgcolor=\"#FFFFFF\" width=\"240\" >\n" + " <tr>\n" + " <td nowrap>" + userNameLabel + "</td>\n" + " <td nowrap><input type=\"text\" name=\"j_username\" " + htmlDisable + "/></td>\n" + " </tr>\n" + " <tr>\n" + " <td nowrap>" + passwordLabel + "</td>\n" + " <td nowrap><input type=\"password\" name=\"j_password\" " + htmlDisable + "/></td>\n" + " </tr>\n" + " <tr>\n" + " <td nowrap height=\"34\"><DIV id=\"vp\"></DIV></td>\n" + " <td nowrap>\n" + " <input type=\"submit\" value=\"" + submitButtonLabel + "\" " + htmlDisable + "/></td>\n" + " </td>\n" + " </tr>\n" + "</table>\n" + "</form>\n" + "<!-- ============================================================= -->" + "\n\n" ; return ( _loginFormBlock); }
page
コンポーネントの上にドラッグします。
Valign
プロパティをmiddle
に設定します。
PanelHorizontal
コンポーネントの上にドラッグします。source
属性を次の値に設定します。
/skins/#{skinBean.currentSkin}/skin_images/LoginSplash.gif
ObjectImage
コンポーネントのすぐ下のpageの上にドラッグします。
ObjectSpacer
要素の下にドラッグします。要求されても、フォームを追加しないでください。これは、後で独自のフォームを追加してデフォルトのフォーム要素を削除するためです。
PanelCustomizable
コンポーネントのLayout
プロパティをvertical
に設定します。
PanelCustomizable
コンポーネントに追加します。
PanelHorizontal
コンポーネントの上にドラッグします。
PanelBox
のText
プロパティを、リソース・バンドルを参照することでログイン・コンポーネント・ヘッダーになるように設定します。そのためには、「データにバインド」アイコンをクリックします。「データにバインド」ダイアログ・ボックスが表示されます。
SRLoginADF.credentialHeader
変数を探します。
PanelBox
コンポーネントの上にドラッグします。
OutputText
コンポーネントのValue
プロパティをマネージドBeanのデータにバインドします(図6-4を参照)。 OutputText
コンポーネントのEscape
プロパティをfalse
に設定します。
Value
プロパティをバッキングBeanのデータにバインドし、Escape
プロパティをfalse
に設定します。
Value
プロパティをバッキングBeanのデータにバインドし、Escape
プロパティをfalse
に設定します。
SRLoginADF.jspx
ページの「構造」ペインで、「panelPag」ノードを開き、Messagesコンポーネントをmessages
ファセットの上にドラッグします。
ログイン・エラー・ページを作成するには、次の手順を実行します。
SRLoginErrorPage.jsp
と入力します。
<html>
要素の直前に追加して、ログイン試行回数を追跡管理します。<!-- =========================================================================== For the SRDemo Demo we will track the number of Login Attempts against the file based repository (In a deployed system this would be handled by the IdM system). This counter is then used in the backing bean to define if the login attempt is valid (referenced in EL as "loginAttemptValid"). =========================================================================== --> <c:set var="LoginErrorCount" scope="session" value="${sessionScope.LoginErrorCount == null ? 1 :sessionScope.LoginErrorCount + 1}"/> <c:redirect url="/faces/infrastructure/SRLoginADF.jspx"/>
このJSTLコードにより、(無効なログインによって)エラー・ページがコールされた回数が単純なセッション変数に格納され、ユーザーは実際の処理が行われている元のログイン・ページにリダイレクトされます。
SRLoginErrorPage.jsp
ファイルを保存します。
「SRLoginADF.java」
を開き、例6-12に示すgetMessages1()
メソッドを追加します。 次の2つのメソッドでは、Faces外部コンテキストを使用してエラー・ページでJSTLによって設定されたセッション変数を返し、ユーザーがログインを試行した回数を特定します。
次のコードは、Facesコンテキストおよび関連付けられたHTTPセッションに基づいてセッション変数を返す方法を示しています。返されたオブジェクトは、ユーザーのログイン試行回数が有効か否かを評価するために、ローカル整数に変換されます。たとえば、試行回数上限3回は次のように適用できます。
FacesContext facesContext = FacesContext.getCurrentInstance(); HttpSession session = (HttpSession)facesContext.getExternalContext().getSession(true); Object loginAttempts = session.getAttribute("LoginErrorCount"); Integer loginAttemptCount = (loginAttempts == null)? 0 : Integer.parseInt(loginAttempts.toString());
/** * =========================================================================== * Function getMessages1() determines the current number of login failures and * sets the appropriate error message in the Faces Context * =========================================================================== * @return */ public CoreMessages getMessages1() { if (!ADFContext.getCurrent().getSecurityContext().isAuthenticated()) { String currentSkin = (String) JSFUtils.getManagedBeanValue("skinBean.currentSkin"); FacesContext facesContext = FacesContext.getCurrentInstance(); HttpSession session = (HttpSession) facesContext.getExternalContext().getSession(true); Object loginAttempts = session.getAttribute("LoginErrorCount"); Integer loginAttemptCount = (loginAttempts == null)? 0 : Integer.parseInt(loginAttempts.toString()); String loginErrorMessage = null; if (loginAttemptCount >0) { if (loginAttemptCount >2) { loginErrorMessage = JSFUtils.getStringFromBundle( "SRLoginADF." + currentSkin + ".tooManyLoginAttempts"); } else { loginErrorMessage = JSFUtils.getStringFromBundle( "SRLoginADF." + currentSkin + ".invalidLogin"); } FacesMessage fm = new FacesMessage( FacesMessage.SEVERITY_INFO,loginErrorMessage,null); facesContext.addMessage(null, fm ); } } return messages1; }
「SRLoginADF.java」
を開き、例6-13に示すisValidLoginAttempt
メソッドを追加します。 isValidLoginAttempt
メソッドから返されるブール値は、ログイン・フォームのHTMLコードが含まれるoutputtextコンポーネントのrenderedプロパティで参照されます。その場合、有効な試行回数が3回を超えるとき、ログイン・フォームはページにレンダリングされず、ユーザーは再度ログインすることができなくなります。
/** * =========================================================================== * Method isValidLoginAttempt() evaluates the number of invalid login attempts * performed by the user and returns false if greater than 3. (used in EL to * show/hide the Login Page components. * =========================================================================== * @return */ public boolean isValidLoginAttempt() { _validLoginAttempt = true; if (!ADFContext.getCurrent().getSecurityContext().isAuthenticated()) { FacesContext facesContext = FacesContext.getCurrentInstance(); HttpSession session = (HttpSession) facesContext.getExternalContext().getSession(true); Object loginAttempts = session.getAttribute("LoginErrorCount"); Integer loginAttemptCount = (loginAttempts == null)? 0 : Integer.parseInt(loginAttempts.toString()); if (loginAttemptCount >2){ _validLoginAttempt = false; } } return (_validLoginAttempt); }
「SRLoginADF.jspx」
を開きます。
OutputText
オブジェクトの下のPanelBox
にドラッグし、source
プロパティを次の値に設定します。
source="/skins/#{skinBean.currentSkin}/skin_images/BadLoginAttempt.gif"
rendered
プロパティをバッキングBeanのisValidLoginAttempt()
メソッドの否定(反対)値にバインドします。rendered
プロパティを次の値に設定します。
#{!backing_infrastructure_SRLoginADF.validLoginAttempt}
この設定により、イメージはログイン試行が無効の場合のみレンダリングされます。
OutputText
オブジェクトのrendered
プロパティを、次のようなisValidLoginAttempt()
メソッドの値に設定します。
#{backing_infrastructure_SRLoginADF.validLoginAttempt}
これで、ログイン・フォームはユーザーのログイン試行が有効な場合のみレンダリングされます。
この項では、リッチ・テキスト・ポートレットをログイン・ページに追加します。そのためには、次の手順を実行します。
panelCustomizable
内の先頭のobjectSpacer
の上にドラッグします。
プロパティ | 値 |
---|---|
AllModesSharedScreen |
true |
IsMinimizable |
false |
IsMaximizable |
false |
DisplayHeader |
false |
panelCustomizable
内の最後のobjectSpacer
の下にドラッグします。
プロパティ | 値 |
---|---|
AllModesSharedScreen |
true |
IsMinimizable |
false |
IsMaximizable |
false |
DisplayHeader |
false |
これで、ログイン後にログイン・ページに戻って、このリッチ・テキスト・ポートレットをカスタマイズできます。その実現方法は、第9章「サイト管理ページの構築」を参照してください。
次に、適切な権限をログイン・ページに定義する必要があります。すべてのユーザーがページを表示できる必要があります。また、管理者は、リッチ・テキスト・ポートレットを更新できるように、ページの編集もできる必要があります。ログイン・ページにセキュリティを設定するには、次の手順を実行します。
この手順では、Oracle ADFセキュリティ・ウィザードを使用してSRDemoアプリケーションの認証設定を構成します。選択したオプションはすべてweb.xml
に記録されます。認証設定を構成するには、次の構成作業を実行する必要があります。
ValidUser
)にadfAuthentication
サーブレットへのアクセス権を付与します。
ADFセキュリティおよびログイン・ページを使用するようにSRDemoアプリケーションを構成するには、次の手順を実行します。
adfAuthentication
サーブレットが構成され、認可ルール(ページに対する現行ユーザーの権限をチェックできる適切なフィルタ)が構成されます。
install.html
ファイルの手順に従ってコピーした、軽量リソース・プロバイダのsystem-jazn-data.xml
を使用します。
ログイン・フォームおよびログイン・エラー・メッセージ(login.html
およびerror.html
)用にデフォルトのページを生成する必要はありません。これは、SRLoginADF.jspx
内にすでに構築したログイン・フォームを使用するためです。
faces/infrastructure/SRLoginADF.jspx
と入力します。
faces/infrastructure/SRLoginErrorPage.jsp
と入力できます(図6-7を参照)。このページは、保護対象となるアプリケーション内のリソースを定義し、各リソースにアクセスできるJ2EEセキュリティ・ロールを指定します。adfAuthentication
リソース(認証サーブレット)が定義されています。このリソースは、編集または削除できませんが、このリソースにアクセスできる一連のロールを指定できます。デフォルトでJ2EEロールが1つ(oc4j-administrators
)選択されていますが、adfAuthentication
リソースには任意の有効なユーザーがアクセスできるようにする必要があるため、ValidUser
という名前のJ2EEロールを別に作成し、このロールにアクセス権を付与する必要があります。
ValidUser
を入力します。後で、このJ2EEロールをIDストアのロールの1つusers
にマップします。これは、このレッスンの始めに定義したロールです。このロールは、すべての有効なユーザーのリストを保持しています。セキュリティの観点から、このロールに権限を割り当てると、認証されたパブリック・リソースが事実上定義されます。つまり、特定の権限を定義する必要なしにすべてのユーザーが使用できるようになります。
ValidUser
ロールがリストに表示されます。
SRWelcome.jspx
ページを実行でき、パブリックにアクセスできるようこそページが表示されます。
sking
)としてログインします。RTPのコンテンツは、通常、サイト管理ページに定義されます。このページは後で構築します。新しいログイン・ページをコールするようにweb.xml
を更新する手順は、次のとおりです。
「web.xml」
プロパティ・パレットを開きます(ポップアップ・メニューから「プロパティ」を選択します)。
adfBindings
フィルタに追加します(図6-8を参照)。必ず、「サーブレット名」にFaces Servlet
と入力し、「フォワード」および「インクルード」の各ディスパッチャ・タイプを選択します。
web.xml
への変更内容を保存します。「SRLoginADF.jspx」
ページを右クリックし、「ページ定義に移動」を選択します。ページ定義ファイルが現在存在しない場合は、そのファイルの作成を確認します。
これで、アプリケーションを実行し、作成したログイン・ページとエラー・ページが正しく表示されるかどうかをテストできます。そのためには、次の手順を実行します。
SRWelcome.jspx
ページを実行します。
デモ・アプリケーションに正常にログインします。
この章では、ADF Facesベースのログイン・ページを構築し、そのログイン・ページを使用するようにSRDemoアプリケーションを構成する方法について学びました。この時点で、管理者が実行時にログイン・ページをカスタマイズできるようにすることができます。この種のカスタマイズを可能にする手順は、第9章「サイト管理ページの構築」を参照してください。
|
![]() Copyright © 2007 Oracle Corporation. All Rights Reserved. |
|