メンバーシップ ユーザー ストアに対してユーザー資格情報を確認する (VB)

作成者: Scott Mitchell

Note

この記事を作成した後で、ASP.NET メンバーシップ プロバイダーよりも ASP.NET Identity のほうが適切になりました。 この記事の作成時点で紹介されている Membership プロバイダーではなく、ASP.NET Identity プラットフォームを使うようにアプリを更新することを強くお勧めします。 ASP.NET メンバーシップ システムと比べると、ASP.NET Identity には次のような多くの利点があります。

  • パフォーマンスの向上
  • 向上した拡張性とテストの容易性
  • OAuth、OpenID Connect、2 要素認証のサポート
  • クレームベースの ID のサポート
  • ASP.Net Core との相互運用性の向上

コードのダウンロードまたは PDF のダウンロード

このチュートリアルでは、プログラムによる手段とログイン コントロールの両方を使用して、メンバーシップ ユーザー ストアに対してユーザーの資格情報を検証する方法について説明します。 また、ログイン コントロールの外観と動作をカスタマイズする方法についても説明します。

はじめに

前のチュートリアルでは、メンバーシップ フレームワークで新しいユーザー アカウントを作成する方法について説明しました。 まず、Membership クラスの CreateUser メソッドを使用してプログラムでユーザー アカウントを作成し、次に CreateUserWizard Web コントロールを使用して調べました。 ただし、現在、ログイン ページでは、指定された資格情報がハードコーディングされたユーザー名とパスワードのペアのリストに対して検証されます。 メンバーシップ フレームワークのユーザー ストアに対して資格情報が検証されるように、ログイン ページのロジックを更新する必要があります。

ユーザー アカウントの作成と同様に、資格情報はプログラムでまたは宣言によって検証できます。 Membership API には、ユーザー ストアに対してユーザーの資格情報をプログラムで検証するためのメソッドが含まれています。 また、ASP.NET には Login Web コントロールが付属しています。これは、ユーザー名とパスワードのテキスト ボックスとログインするためのボタンを含むユーザー インターフェイスをレンダリングします。

このチュートリアルでは、プログラムによる手段とログイン コントロールの両方を使用して、メンバーシップ ユーザー ストアに対してユーザーの資格情報を検証する方法について説明します。 また、ログイン コントロールの外観と動作をカスタマイズする方法についても説明します。 それでは始めましょう。

手順 1: メンバーシップ ユーザー ストアに対してユーザー資格情報を検証する

フォーム認証を使用する Web サイトの場合、ユーザーはログイン ページにアクセスし、資格情報を入力して Web サイトにログオンします。 これらの資格情報は、ユーザー ストアに対して比較されます。 有効な場合、ユーザーにはフォーム認証チケットが付与されます。これは、訪問者の ID と信頼性を示すセキュリティ トークンです。

メンバーシップ フレームワークに対してユーザーを検証するには、Membership クラスの ValidateUser メソッドを使用します。 ValidateUser メソッドは、usernamepassword の 2 つの入力パラメーターを受け取り、資格情報が有効かどうかを示すブール値を返します。 前のチュートリアルで確認した CreateUser メソッドと同様に、ValidateUser メソッドは 実際の検証を構成済みのメンバーシップ プロバイダーに委任します。

SqlMembershipProvider は、aspnet_Membership_GetPasswordWithFormat ストアド プロシージャを使用して、指定されたユーザーのパスワードを取得して、指定された資格情報を検証します。 SqlMembershipProvider は、ユーザーのパスワードを、平文、暗号化、ハッシュの 3 つの形式のいずれかを使用して保存することを思い出してください。 aspnet_Membership_GetPasswordWithFormat ストアド プロシージャは、生形式でパスワードを返します。 暗号化またはハッシュされたパスワードの場合、SqlMembershipProviderValidateUser メソッドに渡された password 値を同等の暗号化またはハッシュ状態に変換し、それをデータベースから返されたものと比較します。 データベースに保存されているパスワードが、ユーザーが入力した書式設定されたパスワードと一致する場合、資格情報は有効です。

指定された資格情報がメンバーシップ フレームワークのユーザー ストアに対して検証されるように、ログイン ページ (~/Login.aspx) を更新してみましょう。 このログイン ページは、「フォーム認証の概要」チュートリアルで作成したものです。ユーザー名とパスワード用の 2 つの TextBox、[Remember Me] チェックボックス、[Login] ボタンを含むインターフェイスを作成しました (図 1 を参照)。 このコードは、入力された資格情報を、ハードコーディングされたユーザー名とパスワードのペアのリスト (Scott/password、Jisun/password、Sam/password) に対して検証します。

The Login Page's Interface Includes Two TextBoxes, a CheckBoxList, and a Button

図 1: ログイン ページのインターフェイスには、2 つのテキスト ボックス、CheckBoxList、およびボタンが含まれています (フルサイズの画像を表示するにはクリックします)

ログイン ページのユーザー インターフェイスは変更せずに済みますが、[Login] ボタンの Click イベント ハンドラーを、メンバーシップ フレームワークのユーザー ストアに対してユーザーを検証するコードに置き換える必要があります。 コードが次のようになるように、イベント ハンドラーを更新します。

Protected Sub LoginButton_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles LoginButton.Click

 ' Validate the user against the Membership framework user store
 If Membership.ValidateUser(UserName.Text, Password.Text) Then
 ' Log the user into the site
 FormsAuthentication.RedirectFromLoginPage(UserName.Text, RememberMe.Checked)
 End If
    
 ' If we reach here, the user's credentials were invalid
 InvalidCredentialsMessage.Visible = True
End Sub

このコードは非常に単純です。 まず、指定されたユーザー名とパスワードを渡して、Membership.ValidateUser メソッドを呼び出します。 このメソッドが True を返す場合、ユーザーは FormsAuthentication クラスの RedirectFromLoginPage メソッドを使用してサイトにサインインされます。 (「フォーム認証の概要 チュートリアルで説明したように、FormsAuthentication.RedirectFromLoginPage はフォーム認証チケットを作成し、ユーザーを適切なページにリダイレクトします)。ただし、資格情報が無効な場合は、InvalidCredentialsMessage ラベルが表示され、ユーザー名またはパスワードが正しくなかったことがユーザーに通知されます。

これですべて完了です。

ログイン ページが期待どおりに動作することをテストするには、前のチュートリアルで作成したユーザー アカウントのいずれかでログインを試みます。 または、まだアカウントを作成していない場合は、~/Membership/CreatingUserAccounts.aspx ページからアカウントを作成します。

Note

ユーザーが自分の資格情報を入力してログイン ページ フォームを送信すると、パスワードを含む資格情報がインターネット経由で "プレーンテキスト" で Web サーバーに送信されます。 つまり、ネットワーク トラフィックをスニッフィングしているハッカーは、ユーザー名とパスワードを確認できるということです。 これを防ぐために、Secure Socket Layer (SSL) を使用してネットワーク トラフィックを暗号化することが不可欠です。 これにより、資格情報 (およびページ全体の HTML マークアップ) が、ブラウザーを離れた瞬間から Web サーバーによって受信されるまで暗号化されます。

メンバーシップ フレームワークが無効なログイン試行を処理する方法

訪問者がログイン ページに到達し、資格情報を送信すると、ブラウザーはログイン ページに HTTP 要求を行います。 資格情報が有効な場合、HTTP 応答には Cookie に認証チケットが含まれています。 したがって、サイトに侵入しようとするハッカーは、有効なユーザー名と推測したパスワードを使用して、ログイン ページに HTTP 要求を網羅的に送信するプログラムを作成できます。 パスワードの推測が正しい場合、ログイン ページは認証チケット Cookie を返します。その時点で、プログラムは有効なユーザー名とパスワードのペアに遭遇したことを認識します。 このようなプログラムは、ブルート フォースによって、特にパスワードが弱い場合に、ユーザーのパスワードを見つける可能性があります。

このようなブルート フォース攻撃を防ぐために、メンバーシップ フレームワークは、一定の時間内にログイン試行が一定回数失敗した場合にユーザーをロックアウトします。 正確なパラメーターは、次の 2 つのメンバーシップ プロバイダー構成設定を使用して構成できます。

  • maxInvalidPasswordAttempts - アカウントがロックアウトされるまでに、一定の期間内にユーザーに対して許可される無効なパスワード試行回数を指定します。既定値は 5 です。
  • passwordAttemptWindow - 指定された数の無効なログイン試行によってアカウントがロックアウトされる期間を分単位で示します。既定値は 10 です。

ロックアウトされたユーザーは、管理者にアカウントのロックを解除してもらうまでログインできません。 ユーザーがロックアウトされると、有効な資格情報が指定されている場合でも、ValidateUser メソッドは"常に" False を返します。 この動作により、ハッカーがブルート フォース手法を用いてサイトに侵入する可能性は低くなりますが、パスワードを忘れた、誤って Caps Lock がオンになっていた、またはタイピングの調子が良くない有効なユーザーがロックアウトされてしまう可能性があります。

残念ながら、ユーザー アカウントのロックを解除するための組み込みツールはありません。 アカウントのロックを解除するために、データベースを直接変更することができます。適切なユーザー アカウントの aspnet_Membership テーブル内の IsLockedOut フィールドを変更します。または、ロックアウトされたアカウントを一覧とロックを解除するオプションを表示する Web ベースのインターフェイスを作成します。 今後のチュートリアルで、一般的なユーザー アカウントとロール関連のタスクを実行するための管理インターフェイスの作成について説明します。

Note

ValidateUser メソッドの欠点の 1 つは、指定された資格情報が無効な場合、その理由に関する説明が提供されないことです。 ユーザー ストアに一致するユーザー名とパスワードのペアがない、ユーザーがまだ承認されていない、またはユーザーがロックアウトされているため、資格情報が無効である可能性があります。手順 4 では、ログイン試行が失敗したときに、より詳細なメッセージをユーザーに表示する方法について説明します。

手順 2: Login Web コントロールを使用して資格情報を収集する

Login Web コントロールは、「フォーム認証の概要」チュートリアルで作成したのとよく似た既定のユーザー インターフェイスをレンダリングします。 Login コントロールを使用すると、訪問者の資格情報を収集するためのインターフェイスを作成する手間が省けます。 さらに、Login コントロールは (送信された資格情報が有効であれば) ユーザーを自動的にサインインさせるため、コードを記述する必要がなくなります。

手動で作成したインターフェイスとコードを Login コントロールに置き換えて、Login.aspx を更新してみましょう。 まず、Login.aspx の既存のマークアップとコードを削除します。 完全に削除することも、単にコメント アウトすることもできます。宣言型マークアップをコメント アウトするには、<%----%> の区切り記号で囲みます。 これらの区切り記号は手動で入力できます。または、図 2 に示すように、コメント アウトするテキストを選択し、ツールバーの [選択した行のコメント化] アイコンをクリックします。 同様に、[選択した行のコメント化] アイコンを使用して、分離コード クラスで選択したコードをコメント アウトできます。

Comment Out the Existing Declarative Markup and Source Code in Login.aspx

図 2: Login.aspx の既存の宣言型マークアップとソース コードをコメント アウトする (フルサイズの画像を表示するにはクリックします)

Note

Visual Studio 2005 で宣言型マークアップを表示する場合、[選択した行をコメント化] アイコンは使用できません。 Visual Studio 2008 を使用していない場合は、手動で <%----%> の区切り記号を追加する必要があります。

次に、ツールボックスからページに Login コントロールをドラッグし、その ID プロパティを myLogin に設定します。 この時点で、画面は図 3 のようになります。 Login コントロールの既定のインターフェイスには、ユーザー名とパスワードの TextBox コントロール、[Remember me next time] の CheckBox、[Log In] ボタンが含まれていることに注意してください。 2 つの TextBox の RequiredFieldValidator コントロールもあります。

Add a Login Control to the Page

図 3: Login コントロールをページに追加する (フルサイズの画像を表示するにはクリック)

完了です。 Login コントロールの [Log In] ボタンをクリックすると、ポストバックが発生し、Login コントロールが Membership.ValidateUser メソッドを呼び出し、入力されたユーザー名とパスワードを渡します。 資格情報が無効な場合は、Login コントロールはそのことを示すメッセージを表示します。 ただし、資格情報が有効な場合、Login コントロールはフォーム認証チケットを作成し、ユーザーを適切なページにリダイレクトします。

Login コントロールは、ログインが成功したときにユーザーをリダイレクトする適切なページを決定するために、4 つの要素を使用します。

  • Login コントロールがフォーム認証構成の loginUrl 設定によって定義されたログイン ページ上にあるかどうか。この設定の既定値は Login.aspx です
  • ReturnUrl querystring パラメーターの存在
  • Login コントロールの DestinationUrl プロパティの値
  • フォーム認証の構成設定で指定された defaultUrl 値。この設定の既定値は Default.aspx です

図 4 は、Login コントロールがこれら 4 つのパラメーターを使用して適切なページ決定にたどり着くまでを示しています。

The Login control uses four parameters to arrive at its appropriate page decision.

図 4: Login コントロールをページに追加する (フルサイズの画像を表示するにはクリック)

ブラウザーを使用してサイトにアクセスし、メンバーシップ フレームワークの既存のユーザーとしてログインすることで、Login コントロールをテストします。

Login コントロールでレンダリングされるインターフェイスは、高度に構成可能です。 外観に影響を与えるプロパティは多数あります。さらに、Login コントロールをテンプレートに変換して、ユーザー インターフェイス要素のレイアウトを正確に制御できます。 この手順の残りでは、外観とレイアウトをカスタマイズする方法について説明します。

Login コントロールの外観のカスタマイズ

Login コントロールの既定のプロパティ設定では、タイトル (Log In)、ユーザー 名とパスワードの入力用の TextBox と Label コントロール、[Remember me next time] CheckBox、[Log In] ボタンを含むユーザー インターフェイスがレンダリングされます。 これらの要素の外観はすべて、Login コントロールの多数のプロパティを使用して構成できます。 さらに、プロパティを 1 つまたは 2 つ設定して、新しいユーザー アカウントを作成するためのページへのリンクなど、追加のユーザー インターフェイス要素を追加できます。

ここで少し Login コントロールの外観を整えてみましょう。 Login.aspx ページの上部には Login というテキストが既にあるので、Login コントロールのタイトルは余分です。 そのため、Login コントロールのタイトルを 削除するために、TitleText プロパティの値をクリアします。

2 つの TextBox コントロールの左側にある User Name: と Password: の Label は、それぞれ UserNameLabelTextPasswordLabelText プロパティを使用してカスタマイズできます。 User Name: Label を変更して、Username: にしてみましょう。 Label と TextBox のスタイルは、それぞれ LabelStyleTextBoxStyle プロパティを使用して構成できます。

[Remember me next time] CheckBox の Text プロパティを Login コントロールの RememberMeText プロパティを使用して設定でき、その既定のチェック状態は RememberMeSet プロパティで構成できます (既定値は False)。 次に [Remember me next time] CheckBox が既定でチェックされるように、RememberMeSet プロパティを True に設定します。

Login コントロールには、ユーザー インターフェイス コントロールのレイアウトを調整するための 2 つのプロパティがあります。 TextLayout プロパティは、Username: と Password: Label が対応する TextBox の左側 (既定) に表示されるか、その上に表示されるかを示します。 Orientation プロパティは、ユーザー名とパスワードの入力を垂直方向 (もう一方の入力の上) に配置するか、水平方向に配置するかを示します。 この 2 つのプロパティは既定値のままにしておきますが、結果として得られる効果を確認するために、これら 2 つのプロパティを既定値以外に設定してみることをお勧めします。

Note

次のセクション「Login コントロールのレイアウトの構成」では、テンプレートを使用して、Login コントロールのユーザー インターフェイス要素の正確なレイアウトを定義します。

Login コントールの最後のプロパティ設定として、CreateUserTextCreateUserUrl プロパティを「Not registered yet? Create an account!」 と ~/Membership/CreatingUserAccounts.aspx にそれぞれ設定します。 これにより、前のチュートリアルで作成したページを指すハイパーリンクが Login コントロールのインターフェイスに追加されます。 Login コントロールの HelpPageText および HelpPageUrl プロパティPasswordRecoveryText および PasswordRecoveryUrl プロパティは同じように動作し、ヘルプ ページとパスワード回復ページへのリンクをレンダリングします。

これらのプロパティを変更した後、Login コントロールの宣言型マークアップと外観は、図 5 に示すようになります。

The Login Control's Properties' Values Dictate Its Appearance

図 5: Login コントロールのプロパティ値がその外観を決定する (フルサイズの画像を表示するにはクリックします)

Login コントロールのレイアウトの構成

Login Web コントロールの既定のユーザー インターフェイスは、HTML <table> でインターフェイスをレイアウトします。 しかし、レンダリングされる出力をより細かく制御する必要がある場合はどうでしょうか。 <table> を一連の <div> タグに置き換えたほうが良いかもしれません。 または、アプリケーションで認証に追加の資格情報が必要な場合はどうでしょうか。 たとえば、多くの金融 Web サイトでは、ユーザー名とパスワードだけでなく、個人識別番号 (PIN) やその他の識別情報を提供することもユーザーに求めます。 理由が何であれ、Login コントロールをテンプレートに変換することができ、そこからインターフェイスの宣言型マークアップを明示的に定義できます。

Login コントロールを更新して追加の資格情報を収集するには、次の 2 つを行う必要があります。

  1. 追加の資格情報を収集する Web コントロールを含むように Login コントロールのインターフェイスを更新する。
  2. Login コントロールの内部認証ロジックをオーバーライドして、ユーザー名とパスワードが有効で、かつ追加の資格情報も有効な場合にのみユーザーが認証されるようにする。

最初のタスクを実行するには、Login コントロールをテンプレートに変換し、必要な Web コントロールを追加する必要があります。 2 番目のタスクに関しては、コントロールの Authenticate イベントのイベント ハンドラーを作成することで、Login コントロールの認証ロジックを置き換えることができます。

ユーザーにユーザー名、パスワード、メール アドレスの入力を求め、指定されたメール アドレスがファイル上のメール アドレスと一致する場合にのみユーザーを認証するように、Login コントロールを更新しましょう。 まず、Login コントロールのインターフェイスをテンプレートに変換する必要があります。 ログイン コントロールのスマート タグから、[Convert to template] (テンプレートに変換) オプションを選択します。

Convert the Login Control to a Template

図 6: Login コントロールをテンプレートに変換する (フルサイズの画像を表示するにはクリックします)

Note

Login コントロールをテンプレート前のバージョンに戻すには、コントロールのスマート タグから [リセット] リンクをクリックします。

Login コントロールをテンプレートに変換すると、ユーザー インターフェイスを定義する HTML 要素と Web コントロールを含む LayoutTemplate がコントロールの宣言型マークアップに追加されます。 図 7 に示すように、コントロールをテンプレートに変換すると、テンプレートの [プロパティ] ウィンドウから TitleTextCreateUserUrl などのいくつかのプロパティが削除されます。これらのプロパティ値はテンプレートの使用時には無視されるためです。

Fewer Properties are Available When the Login Control is Converted to a Template

図 7: Login コントロールがテンプレートに変換されるときに使用できるプロパティが少なくなる (フルサイズの画像を表示するにはクリックします)

LayoutTemplate 内の HTML マークアップは、必要に応じて変更できます。 同様に、テンプレートに新しい Web コントロールを自由に追加できます。 ただし、Login コントロールのコア Web コントロールをテンプレートに残し、割り当てられた ID 値を維持することが重要です。 特に、UserName および Password TextBox、RememberMe CheckBox、LoginButton Button、FailureText Label、および RequiredFieldValidator コントロールを削除したり、名前を変更したりしないでください。

訪問者のメール アドレスを収集するために、テンプレートに TextBox を追加する必要があります。 Password TextBox を含むテーブル行 (<tr>) と、[Remember me next time] CheckBox を保持するテーブル行の間に、次の宣言型マークアップを追加します。

<tr>
 <td align="right">
 <asp:Label ID="EmailLabel" runat="server" AssociatedControlID="Email">Email:</asp:Label>
 </td>
 <td>
 <asp:TextBox ID="Email" runat="server"></asp:TextBox>
 <asp:RequiredFieldValidator ID="EmailRequired" runat="server"
 ControlToValidate="Email" ErrorMessage="Email is required."
 ToolTip="Email is required." ValidationGroup="myLogin">*</asp:RequiredFieldValidator>
 </td>
</tr>

Email TextBox を追加した後、ブラウザーを使用してページにアクセスします。 図 8 に示すように、Login コントロールのユーザー インターフェイスに 3 番目のテキスト ボックスが含まれるようになります。

The Login Control Now Includes a Textbox for the User's Email Address

図 8: ユーザーのメール アドレス用のテキスト ボックスが含まれるようになった Login コントロール (フルサイズの画像を表示するにはクリックします)

この時点で、Login コントロールは引き続き Membership.ValidateUser メソッドを使用して指定された資格情報を検証しています。 そのため、Email TextBox に入力された値は、ユーザーがログインできるかどうかに関係しません。 手順 3 では、Login コントロールの認証ロジックをオーバーライドして、ユーザー名とパスワードが有効で、かつ指定されたメール アドレスがファイルのメール アドレスと一致する場合にのみ資格情報が有効と見なされるようにする方法について説明します。

手順 3: Login コントロールの認証ロジックを変更する

訪問者が資格情報を入力してログイン ボタンをクリックすると、ポストバックが発生し、Login コントロールが認証ワークフローを通じて進行します。 ワークフローは、LoggingIn イベントを発生させて開始します。 このイベントに関連付けられているイベント ハンドラーは、e.Cancel プロパティを True に設定することで、ログイン操作を取り消すことができます。

ログイン操作が取り消されない場合は、Authenticate イベントを発生させることでワークフローが進行します。 Authenticate イベントのイベント ハンドラーがある場合は、指定された資格情報が有効かどうかをそこで判断する必要があります。 イベント ハンドラーが指定されていない場合、Login コントロールは Membership.ValidateUser メソッドを使用して資格情報の有効性を判断します。

指定された資格情報が有効な場合は、フォーム認証チケットが作成され、LoggedIn イベントが発生し、ユーザーは適切なページにリダイレクトされます。 ただし、資格情報が無効と見なされた場合は、LoginError イベントが発生し、資格情報が無効であることをユーザーに通知するメッセージが表示されます。 既定では、失敗した場合、Login コントロールは単に FailureText Label コントロールの Text プロパティを次のエラー メッセージに設定します (Your login attempt was not successful.Please try again)。 ただし、Login コントロールの FailureAction プロパティRedirectToLoginPage に設定されている場合、Login コントロールは、querystring パラメーター loginfailure=1 を追加してログイン ページに Response.Redirect を発行します (これにより、Login コントロールにエラー メッセージが表示されます)。

図 9 は、認証ワークフローのフロー チャートを示しています。

The Login Control's Authentication Workflow

図 9: Login コントロールの認証ワークフロー (フルサイズの画像を表示するにはクリックします)

Note

FailureActionRedirectToLogin オプションをいつ使用するのか疑問に思う場合は、次のシナリオを考えてみてください。 現在、Site.master マスター ページには、匿名ユーザーがアクセスしたときに「Hello, stranger」というテキストが表示されますが、そのテキストを Login コントロールに置き換えるとします。 これにより、匿名ユーザーはサイト上の任意のページからログインでき、ログイン ページに直接アクセスする必要はありません。 ただし、ユーザーがマスター ページによってレンダリングされた Login コントロールを使用してログインできなかった場合、そのユーザーをログイン ページ (Login.aspx) にリダイレクトすることが理にかなっている可能性があります。そのページには、マスター ページに追加されていない追加の手順、リンク、その他のヘルプ (新しいアカウントの作成や忘れたパスワードを取得するためのリンクなど) が含まれている可能性があるためです。

Authenticate イベント ハンドラーの作成

カスタム認証ロジックをプラグインするには、Login コントロールの Authenticate イベントのイベント ハンドラーを作成する必要があります。 Authenticate イベントのイベント ハンドラーを作成すると、次のイベント ハンドラー定義が生成されます。

Protected Sub myLogin_Authenticate(ByVal sender As Object, ByVal e As System.Web.UI.WebControls.AuthenticateEventArgs) Handles myLogin.Authenticate

End Sub

見てのとおり、Authenticate イベント ハンドラーには、2 番目の入力パラメーターとして型 AuthenticateEventArgs のオブジェクトが渡されます。 AuthenticateEventArgs クラスには、指定された資格情報が有効かどうかを指定するために使用されるブール値プロパティ Authenticated が含まれています。 ここでのタスクは、指定された資格情報が有効かどうかを判断し、それに応じて e.Authenticate プロパティを設定するコードを記述することです。

指定された資格情報の判別と検証

Login コントロールの UserNamePassword プロパティを使用して、ユーザーが入力したユーザー名とパスワードの資格情報を判別します。 追加の Web コントロール (前の手順で追加した Email TextBox など) に入力された値を確認するには、LoginControlID.FindControl("controlID") を使用して、ID プロパティが controlID に等しいテンプレート内の Web コントロールへのプログラムによる参照を取得します。 たとえば、Email TextBox への参照を取得するには、次のコードを使用します。

Dim EmailTextBox As TextBox = CType(myLogin.FindControl("Email"), TextBox)

ユーザーの資格情報を検証するには、次の 2 つのことを行う必要があります。

  1. 指定されたユーザー名とパスワードが正しいことを確認する
  2. 入力されたメール アドレスが、ログインしようとしているユーザーのファイルのメール アドレスと一致していることを確認する

最初のチェックを実現するには、手順 1 と同じように Membership.ValidateUser メソッドを使用できます。 2 番目のチェックでは、TextBox コントロールに入力されたメール アドレスと比較できるように、ユーザーのメール アドレスを特定する必要があります。 特定のユーザーに関する情報を取得するには、Membership クラスの GetUser メソッドを使用します。

この GetUser メソッドには、いくつかのオーバーロードがあります。 パラメーターを渡さずに使用すると、現在ログインしているユーザーに関する情報が返されます。 特定のユーザーに関する情報を取得するには、ユーザー名を渡して GetUser を呼び出します。 いずれの場合でも、GetUserMembershipUser オブジェクトを返します。これには、UserNameEmailIsApprovedIsOnline などのプロパティがあります。

次のコードでは、これら 2 つのチェックを実装しています。 両方に合格した場合、e.AuthenticateTrue に設定され、それ以外の場合は False が割り当てられます。

Protected Sub myLogin_Authenticate(ByVal sender As Object, ByVal e As System.Web.UI.WebControls.AuthenticateEventArgs) Handles myLogin.Authenticate
    
 ' Get the email address entered
 Dim EmailTextBox As TextBox = CType(myLogin.FindControl("Email"), TextBox)
 Dim email As String = EmailTextBox.Text.Trim()
    
 ' Verify that the username/password pair is valid
 If Membership.ValidateUser(myLogin.UserName, myLogin.Password) Then

 ' Username/password are valid, check email
 Dim usrInfo As MembershipUser = Membership.GetUser(myLogin.UserName)
    
 If usrInfo IsNot Nothing AndAlso String.Compare(usrInfo.Email, email, True) = 0 Then
 ' Email matches, the credentials are valid
 e.Authenticated = True
 Else
 ' Email address is invalid...
 e.Authenticated = False
 End If
 Else
 ' Username/password are not valid...
 e.Authenticated = False
 End If
End Sub

このコードを設定した状態で、正しいユーザー名、パスワード、メール アドレスを入力して、有効なユーザーとしてログインを試みます。 もう一度試してみてくださいが、今回は意図的に間違ったメール アドレスを使用します (図 10 を参照)。 最後に、3 回目は存在しないユーザー名を使用して試してみてください。 最初のケースではサイトに正常にログオンしますが、最後の 2 つのケースでは、Login コントロールの無効な資格情報メッセージが表示されます。

Tito Cannot Log In When Supplying an Incorrect Email Address

図 10: 正しくないメール アドレスを指定すると、Tito はログインできない (フルサイズの画像を表示するにはクリックします)

Note

手順 1 の「メンバーシップ フレームワークでの無効なログイン試行の処理方法」セクションで説明したように、Membership.ValidateUser メソッドが呼び出され、無効な資格情報が渡されると、無効なログイン試行が追跡され、指定された時間枠内での無効な試行のしきい値を超えた場合にユーザーはロックアウトされます。 カスタム認証ロジックによって ValidateUser メソッドが呼び出されるため、有効なユーザー名のパスワードが正しくないと、無効なログイン試行のカウンターがインクリメントされますが、ユーザー名とパスワードが有効であるのにメール アドレスが正しくない場合、このカウンターはインクリメントされません。 ハッカーがユーザー名とパスワードを入手するが、ブルート フォース手法を使用してユーザーのメール アドレスを特定しなければならない可能性は低いため、この動作は問題がない可能性が高いと言えます。

手順 4: Login コントロールの無効な資格情報メッセージの改善

ユーザーが無効な資格情報でログオンしようとすると、ログインの試行が失敗したことを示すメッセージが Login コントロールに表示されます。 具体的には、コントロールは、そのFailureText プロパティで指定されたメッセージを表示します。これには、「Your login attempt was not successful」という既定値があります。 もう一度やり直してください。

ユーザーの資格情報が無効になる理由は多数あることを思い出してください。

  • ユーザー名が存在しない可能性があります
  • ユーザー名は存在するが、パスワードが無効です
  • ユーザー名とパスワードは有効ですが、ユーザーはまだ承認されていません
  • ユーザー名とパスワードは有効ですが、ユーザーはロックアウトされています (指定された期間内に無効なログイン試行回数を超えた可能性が最も高い)

また、カスタム認証ロジックを使用する他の理由が考えられる場合があります。 たとえば、手順 3 で記述したコードでは、ユーザー名とパスワードは有効ですが、メール アドレスが正しくない可能性があります。

資格情報が無効な理由に関係なく、Login コントロールには同じエラー メッセージが表示されます。 このフィードバックの欠如は、アカウントがまだ承認されていないユーザーやロックアウトされているユーザーにとって混乱を招く可能性があります。ただし、少し作業するだけで、Login コントロールにより適切なメッセージを表示させることができます。

ユーザーが無効な資格情報でログインしようとするたびに、Login コントロールによって LoginError イベントが生成されます。 このイベントのイベント ハンドラーを作成し、次のコードを追加します。

Protected Sub myLogin_LoginError(ByVal sender As Object, ByVal e As System.EventArgs) Handles myLogin.LoginError
    
 ' Determine why the user could not login...
 myLogin.FailureText = "Your login attempt was not successful. Please try again."
    
 ' Does there exist a User account for this user?
 Dim usrInfo As MembershipUser = Membership.GetUser(myLogin.UserName)

 If usrInfo IsNot Nothing Then
 ' Is this user locked out?
 If usrInfo.IsLockedOut Then
 myLogin.FailureText = "Your account has been locked out because of too many invalid login attempts. Please contact the administrator to have your account unlocked."
 ElseIf Not usrInfo.IsApproved Then
 myLogin.FailureText = "Your account has not yet been approved. You cannot login until an administrator has approved your account."
 End If
 End If
End Sub

上のコードは、まず Login コントロールの FailureText プロパティを既定値に設定します (Your login attempt was not successful.Please try again)。 次に、指定されたユーザー名が既存のユーザー アカウントにマップされているかどうかを確認します。 されている場合は、結果の MembershipUser オブジェクトの IsLockedOutIsApproved プロパティを調べて、アカウントがロックアウトされているか、まだ承認されていないかを判断します。 どちらの場合も、FailureText プロパティは対応する値に更新されます。

このコードをテストするには、既存のユーザーとしてログインを試みますが、意図的に正しくないパスワードを使用してください。 これを 10 分以内に 5 回連続して実行すると、アカウントがロックアウトされます。図 11 に示すように、それ以降のログイン試行は (正しいパスワードでも) 常に失敗しますが、より説明的な「Your account has been locked out because of too many invalid login attempts. Please contact the administrator to have your account unlocked」というメッセージが表示されます。

Tito Performed Too Many Invalid Login Attempts and Has Been Locked Out

図 11: Tito は無効なログイン試行を実行しすぎてロックアウトされている (フルサイズの画像を表示するにはクリックします)

まとめ

このチュートリアルの前、ログイン ページでは、指定された資格情報を、ユーザー名とパスワードのペアのハードコーディングされたリストに対して検証していました。 このチュートリアルでは、メンバーシップ フレームワークに対して資格情報を検証するようにページを更新しました。 手順 1 では、プログラムによる Membership.ValidateUser メソッドの使用について説明しました。 手順 2 では、手動で作成したユーザー インターフェイスとコードを Login コントロールに置き換えました。

Login コントロールは、標準のログイン ユーザー インターフェイスをレンダリングし、ユーザーの資格情報をメンバーシップ フレームワークに対して自動的に検証します。 さらに、資格情報が有効な場合、Login コントロールはフォーム認証を使用してユーザーをサインインさせます。 つまり、Login コントロールをページにドラッグするだけで、完全に機能するログイン ユーザー エクスペリエンスを利用できます。追加の宣言型マークアップやコードは必要ありません。 さらに、Login コントロールは高度にカスタマイズ可能であり、レンダリングされるユーザー インターフェイスと認証ロジックの両方を細かく制御できます。

この時点で、この Web サイトの訪問者は新しいユーザー アカウントを作成してサイトにログインできますが、認証されたユーザーに基づいてページへのアクセスを制限する方法はまだ説明していません。 現在、認証済みまたは匿名のすべてのユーザーが、サイト上の任意のページを表示できます。 ユーザーごとにサイトのページへのアクセスを制御する一方で、ユーザーに依存する機能を持つ特定のページがある場合があります。 次のチュートリアルでは、ログインしているユーザーに基づいてアクセスとページ内機能を制限する方法について説明します。

プログラミングに満足!

もっと読む

この記事で説明したトピックの詳細については、次のリソースを参照してください。

作成者について

複数の ASP/ASP.NET 書籍の著者であり、4GuysFromRolla.com の創設者である Scott Mitchell は、1998 年から Microsoft Web テクノロジに取り組んでいます。 Scott は、独立したコンサルタント、トレーナー、ライターとして働いています。 彼の最新の本は サムズは24時間で2.0 ASP.NET 自分自身を教えています。 Scott には、mitchell@4guysfromrolla.com または http://ScottOnWriting.NET のブログを介して連絡できます。

特別な感謝

このチュートリアル シリーズは、多くの役に立つ校閲者によってレビューされました。 このチュートリアルのリード レビュー担当者は、Teresa Murphy と Michael Olivero でした。 今後の MSDN の記事を確認することに関心がありますか? その場合は、mitchell@4GuysFromRolla.com までご一報ください。