| 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. |
|