ユーザー アカウントを作成する (C#)

作成者: Scott Mitchell

Note

この記事の作成以降に、ASP.NET Membership プロバイダーは ASP.NET Identity に置き換えられました。 アプリを更新し、この記事が作成された時点で紹介した Membership プロバイダーではなく、 ASP.NET Identity プラットフォームを使用することを強くお勧めします。 ASP.NET Membership システムと比較すると、ASP.NET Identity には次のような多くの利点があります。

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

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

このチュートリアルでは、Membership フレームワークを使って (SqlMembershipProvider を使用) 新しいユーザー アカウントを作成する方法について調べます。 プログラムと ASP.NET の組み込みの CreateUserWizard コントロールを使用して、新しいユーザーを作成する方法を確認します。

はじめに

前のチュートリアルでは、アプリケーション サービス スキーマをデータベースにインストールしました。これにより、SqlMembershipProviderSqlRoleProvider に必要なテーブル、ビュー、ストアド プロシージャが追加されました。 これにより、このシリーズのチュートリアルの残りの部分に必要なインフラストラクチャが作成されました。 このチュートリアルでは、Membership フレームワークを使って (SqlMembershipProvider を使用) 新しいユーザー アカウントを作成する方法について調べます。 プログラムと ASP.NET の組み込みの CreateUserWizard コントロールを使用して、新しいユーザーを作成する方法を確認します。

新しいユーザー アカウントを作成する方法を学習するだけでなく、「フォーム認証の概要」チュートリアルで最初に作成したデモ Web サイトを更新してから、「フォーム認証構成と高度なトピック」チュートリアルで拡張する必要もあります。 デモ Web アプリケーションには、ハードコーディングされたユーザー名とパスワードのペアに対してユーザーの資格情報を検証するログイン ページがあります。 さらに、Global.asax には、認証されたユーザーのカスタム IPrincipal および IIdentity オブジェクトを作成するコードが含まれています。 Membership フレームワークに対してユーザーの資格情報を検証し、カスタム プリンシパルと ID ロジックを削除するように、ログイン ページを更新します。

それでは始めましょう。

フォーム認証と Membership のチェックリスト

Membership フレームワークで作業を開始する前に、少し時間を取って、これまでに行った重要な手順を確認しましょう。 フォーム ベース認証シナリオで Membership フレームワークを SqlMembershipProvider と共に使用する場合は、Web アプリケーションに Membership 機能を実装する前に、次の手順を行う必要があります。

  1. フォーム ベース認証を有効にします。フォーム認証の概要」で説明したように、フォーム認証は、Web.config を編集し、<authentication> 要素の mode 属性を Forms に設定することで有効になります。 フォーム認証が有効になっている場合、各受信要求では、要求元を識別する "フォーム認証チケット" (存在する場合) が確認されます。
  2. アプリケーション サービス スキーマを適切なデータベースに追加します。 SqlMembershipProvider を使用する場合は、アプリケーション サービス スキーマをデータベースにインストールする必要があります。 通常、このスキーマは、アプリケーションのデータ モデルを保持する同じデータベースに追加されます。 「SQL Server での Membership スキーマの作成」チュートリアルでは、aspnet_regsql.exe ツールを使用してこれを行う方法について確認しました。
  3. 手順 2 のデータベースを参照するように Web アプリケーションの設定をカスタマイズします。 「SQL Server での Membership スキーマの作成」チュートリアルでは、SqlMembershipProvider が手順 2 で選択されたデータベースを使用するように Web アプリケーションを構成する 2 つの方法を示しました。つまり、LocalSqlServer 接続文字列名を変更する方法と、Membership フレームワーク プロバイダーのリストに新しい登録済みプロバイダーを追加し、手順 2 のデータベースを使用するように新しいプロバイダーをカスタマイズする方法です。

SqlMembershipProvider とフォーム ベース認証を使用する Web アプリケーションを構築する場合は、Membership クラスまたは ASP.NET Login Web コントロールを使う前に、次の 3 つの手順を行う必要があります。 前のチュートリアルでこれらの手順を既に行っているため、Membership フレームワークの使用を開始する準備はできています。

手順 1: 新しい ASP.NET ページの追加

これと次の 3 つのチュートリアルでは、Membership 関連のさまざまな機能について確認します。 これらのチュートリアル全体で確認するトピックを実装するには、一連の ASP.NET ページが必要です。 これらのページを作成し、サイト マップ ファイル (Web.sitemap) を作成してみましょう。

まず、プロジェクトに Membership という名前の新しいフォルダーを作成します。 次に、5 つの新しい ASP.NET ページを Membership フォルダーに追加し、各ページを Site.master マスター ページにリンクします。 ページに次の名前を付けます。

  • CreatingUserAccounts.aspx
  • UserBasedAuthorization.aspx
  • EnhancedCreateUserWizard.aspx
  • AdditionalUserInfo.aspx
  • Guestbook.aspx

この時点で、プロジェクトのソリューション エクスプローラーは、図 1 に示すスクリーンショットのようになるはずです。

Five New Pages Have Been Added to the Membership Folder

図 1: Membership フォルダーに 5 つの新しいページが追加された (クリックするとフルサイズの画像を表示されます)

この時点で、各ページには、マスター ページの ContentPlaceHolders ごとに 1 つずつ、MainContentLoginContent という 2 つの Content コントロールがあるはずです。

<asp:Content ID="Content1" ContentPlaceHolderID="MainContent"

Runat="Server">
</asp:Content>
<asp:Content ID="Content2" ContentPlaceHolderID="LoginContent"
Runat="Server">
</asp:Content>

LoginContent ContentPlaceHolder の既定のマークアップでは、ユーザーが認証されているかどうかに応じて、サイトにログオンまたはログオフするためのリンクが表示されることを思い出してください。 ただし、Content2 Content コントロールが存在すると、マスター ページの既定のマークアップがオーバーライドされます。 「フォーム認証の概要」チュートリアルで説明したように、これは、左側の列にログイン関連のオプションを表示しないページで役立ちます。

しかし、これら 5 つのページでは、LoginContent ContentPlaceHolder のマスター ページの既定のマークアップを表示したいと考えています。 そのため、Content2 Content コントロールの宣言型マークアップを削除します。 その後、5 つのページのマークアップのそれぞれには 1 つの Content コントロールのみが含まれるはずです。

手順 2: サイト マップの作成

最も簡単な Web サイト以外はすべて、何らかの形式のナビゲーション ユーザー インターフェイスを実装する必要があります。 ナビゲーション ユーザー インターフェイスは、サイトのさまざまなセクションへのリンクのシンプルなリストである場合があります。 これらのリンクはメニューまたはツリー ビューに配置される場合もあります。 ページ開発者として、ナビゲーション ユーザー インターフェイスを作成することは、ストーリーの半分にすぎません。 保守可能かつ更新可能な方法でサイトの論理構造を定義するための手段もいくつか必要です。 新しいページが追加されたり、既存のページが削除されたりすると、1 つのソース (サイト マップ) を更新し、それらの変更をサイトのナビゲーション ユーザー インターフェイス全体に反映できるようにしたいと考えています。

サイト マップの定義とサイト マップに基づくナビゲーション ユーザー インターフェイスの実装という 2 つのタスクは、Site Map フレームワークと、ASP.NET バージョン 2.0 で追加された Navigation Web コントロールのおかげで簡単に実行できます。 Site Map フレームワークを使用すると、開発者はサイト マップを定義し、プログラム API (SiteMap クラス) を使用してアクセスできます。 組み込みの Navigation Web コントロールには、Menu コントロールTreeView コントロールSiteMapPath コントロールが含まれます。

Membership と Roles フレームワークと同様に、Site Map フレームワークはプロバイダー モデルの上に構築されます。 Site Map プロバイダー クラスのジョブは、XML ファイルやデータベース テーブルなどの永続的なデータ ストアから、SiteMap クラスによって使用されるインメモリ構造を生成することです。 .NET Framework には、XML ファイルからサイト マップ データを読み取る既定の Site Map プロバイダー (XmlSiteMapProvider) が付属しています。これは、このチュートリアルで使用するプロバイダーです。 いくつかの代替 Site Mapプロバイダーの実装については、このチュートリアルの最後にある「参考資料」セクションを参照してください。

既定の Site Map プロバイダーでは、ルート ディレクトリが存在する Web.sitemap という名前の適切な形式の XML ファイルが必要です。 この既定のプロバイダーを使用しているため、このようなファイルを追加し、適切な XML 形式でサイト マップの構造を定義する必要があります。 ファイルを追加するには、ソリューション エクスプローラーでプロジェクト名を右クリックし、[新しい項目の追加] を選択します。 ダイアログ ボックスから、Web.sitemap という名前の Site Map の種類のファイルを追加することを選択します。

Add a File Named Web.sitemap to the Project's Root Directory

図 2: プロジェクトのルート ディレクトリに Web.sitemap という名前のファイルを追加する (クリックするとフルサイズの画像が表示されます)

XML サイト マップ ファイルでは、Web サイトの構造が階層として定義されます。 この階層関係は、<siteMapNode> 要素の先祖を介して XML ファイルでモデル化されます。 Web.sitemap は、<siteMapNode> 子が 1 つだけの <siteMap> 親ノードで始まる必要があります。 この最上位の <siteMapNode> 要素は階層のルートを表し、任意の数の子孫ノードを持つことができます。 各 <siteMapNode> 要素には title 属性を含める必要があり、必要に応じて、特に urldescription 属性を含めることができます。空でない各 url 属性は一意である必要があります。

Web.sitemap ファイルに次の XML を入力します。

<?xml version="1.0" encoding="utf-8" ?>

<siteMap xmlns="http://schemas.microsoft.com/AspNet/SiteMap-File-1.0" >
     <siteMapNode url="~/Default.aspx" title="Home">
          <siteMapNode title="Membership">
               <siteMapNode url="~/Membership/CreatingUserAccounts.aspx" title="Creating User Accounts" />

               <siteMapNode url="~/Membership/UserBasedAuthorization.aspx" title="User-Based Authorization" />
               <siteMapNode url="~/Membership/Guestbook.aspx" title="Storing Additional User Information" />
          </siteMapNode>

     </siteMapNode>
</siteMap>

上のサイト マップ マークアップでは、図 3 に示されている階層が定義されています。

The Site Map Represents a Hierarchical Navigational Structure

図 3: サイト マップが階層ナビゲーション構造を表している (クリックするとフルサイズ画像が表示されます)

手順 3: ナビゲーション ユーザー インターフェイスを含むようにマスター ページを更新する

ASP.NET には、ユーザー インターフェイスを設計するためのナビゲーション関連の Web コントロールが多数含まれています。 これには、Menu、TreeView、および SiteMapPath コントロールが含まれます。 Menu と TreeView コントロールでは、それぞれメニューまたはツリーにサイト マップ構造がレンダリングされます。一方、SiteMapPath では、アクセスされている現在のノードとその先祖を示す階層リンクが表示されます。 サイト マップ データは、SiteMapDataSource を使用して他のデータ Web コントロールにバインドでき、SiteMap クラスを介してプログラムでアクセスできます。

Site Map フレームワークと Navigation コントロールの詳細な説明は、このチュートリアル シリーズの範囲外であるため、独自のナビゲーション ユーザー インターフェイスの作成に時間を費やすのではなく、図 4 に示すように、ナビゲーション リンクの深さ 2 の箇条書きを表示するために Repeater コントロールを使用する、「ASP.NET 2.0 でのデータ操作」チュートリアル シリーズで使用するものを代わりに借用しましょう。

このインターフェイスを作成するには、次の宣言型マークアップを Site.master マスター ページの左側の列に追加します。ここには現在、"TODO: Menu will go here..." というテキストがあります。

<ul>
     <li>

          <asp:HyperLink runat="server" ID="lnkHome" NavigateUrl="~/Default.aspx">Home</asp:HyperLink>
     </li>
     <asp:Repeater runat="server" ID="menu" DataSourceID="SiteMapDataSource1">

          <ItemTemplate>
               <li>
                    <asp:HyperLink ID="lnkMenuItem" runat="server" 
                         NavigateUrl='<%# Eval("Url") %>'><%# Eval("Title") %></asp:HyperLink>

                    <asp:Repeater ID="submenu" runat="server" DataSource="<%#
                         ((SiteMapNode) Container.DataItem).ChildNodes %>">
                         <HeaderTemplate>
                              <ul>
                         </HeaderTemplate>
                         <ItemTemplate>

                              <li>
                                   <asp:HyperLink ID="lnkMenuItem" runat="server" NavigateUrl='<%#
                                        Eval("Url") %>'><%# Eval("Title") %></asp:HyperLink>

                              </li>
                         </ItemTemplate>
                         <FooterTemplate>
                              </ul>
                         </FooterTemplate>
                    </asp:Repeater>
               </li>
          </ItemTemplate>
     </asp:Repeater>

</ul>
    
<asp:SiteMapDataSource ID="SiteMapDataSource1" runat="server" ShowStartingNode="false" />

上記のマークアップでは、menu という名前の Repeater コントロールが SiteMapDataSource にバインドされ、Web.sitemap で定義されているサイト マップ階層が返されます。 SiteMapDataSource コントロールの ShowStartingNode プロパティが False に設定されているため、"Home" ノードの子孫から始まるサイト マップの階層を返す作業が開始されます。 Repeater では、これらの各ノード (現在は "Membership" のみ) が <li> 要素に表示されます。 その後、別の内部 Repeater では、現在のノードの子が入れ子になった順序なしのリストに表示されます。

図 4 は、上記のマークアップのレンダリングされた出力と、手順 2 で作成したサイト マップ構造を示しています。 Repeater では、バニラの順序なしリスト マークアップがレンダリングされます。Styles.css で定義されているカスケード スタイル シートの規則の役割は、見た目が美しいレイアウトにすることです。 上記のマークアップのしくみの詳細については、「マスター ページとサイト ナビゲーション」チュートリアルを参照してください。

The Navigational User Interface is Rendered Using Nested Unordered Lists

図 4: 入れ子になった順序なしリストを使用してナビゲーション ユーザー インターフェイスがレンダリングされている (クリックするとフルサイズの画像が表示されます)

階層リンク ナビゲーションの追加

左側の列のリンクのリストに加え、各ページに階層リンクも表示させてみましょう。 階層リンクは、サイト階層内のユーザーの現在の位置をすばやく表示するナビゲーション ユーザー インターフェイス要素です。 SiteMapPath コントロールでは、Site Map フレームワークを使用してサイト マップ内の現在のページの場所を判断し、この情報に基づいて階層リンクを表示します。

具体的には、マスター ページのヘッダー <div> 要素に <span> 要素を追加し、新しい <span> 要素の class 属性を "breadcrumb" に設定します (Styles.css クラスには、"breadcrumb" クラスの規則が含まれています)。次に、この新しい <span> 要素に SiteMapPath を追加します。

<div id="header">
     <span class="title">User Account Tutorials</span><br />
     <span class="breadcrumb">
          <asp:SiteMapPath ID="SiteMapPath1" runat="server">

          </asp:SiteMapPath>
     </span>
</div>

図 5 には、~/Membership/CreatingUserAccounts.aspx にアクセスしたときの SiteMapPath の出力が示されています。

The Breadcrumb Displays the Current Page and its Ancestors in the Site Map

図 5: 階層リンクでは、現在のページとその先祖がサイト マップに表示される (クリックするとフルサイズの画像が表示されます)

手順 4: カスタム プリンシパルと ID ロジックの削除

カスタム プリンシパルおよび ID オブジェクトは、認証されたユーザーに関連付けることができます。 これを実現するには、FormsAuthenticationModule でユーザーが認証された後に発生する、アプリケーションの PostAuthenticateRequest イベントの Global.asax にイベント ハンドラーを作成します。 このイベント ハンドラーでは、FormsAuthenticationModule によって追加された GenericPrincipalFormsIdentity オブジェクトを、そのチュートリアルで作成した CustomPrincipalCustomIdentity オブジェクトに置き換えました。

カスタム プリンシパルおよび ID オブジェクトは特定のシナリオで役立ちますが、ほとんどの場合、GenericPrincipalFormsIdentity オブジェクトで十分です。 したがって、既定の動作に戻す価値があると考えます。 この変更を行うには、PostAuthenticateRequest イベント ハンドラーを削除またはコメント アウトするか、Global.asax ファイルを完全に削除します。

手順 5: プログラムによる新しいユーザーの作成

Membership フレームワークを使って新しいユーザー アカウントを作成するには、Membership クラスの CreateUser メソッドを使用します。 このメソッドには、ユーザー名、パスワード、およびその他のユーザー関連フィールドの入力パラメーターがあります。 呼び出し時に、新しいユーザー アカウントの作成が構成済みの Membership プロバイダーに委任され、作成したばかりのユーザー アカウントを表す MembershipUser オブジェクトが返されます。

CreateUser メソッドには、それぞれ異なる数の入力パラメーターを受け入れる 4 つのオーバーロードがあります。

これら 4 つのオーバーロードは、収集される情報の量によって異なります。 たとえば、最初のオーバーロードでは、新しいユーザー アカウントのユーザー名とパスワードだけが必要ですが、2 つ目のオーバーロードではユーザーのメール アドレスも必要です。

これらのオーバーロードが存在するのは、新しいユーザー アカウントの作成に必要な情報が Membership プロバイダーの構成設定によって異なるためです。 「SQL Server での Membership スキーマの作成」チュートリアルで、Web.config での Membership プロバイダーの構成設定の指定について確認しました。 表 2 には、構成設定の完全なリストが含まれていました。

使用される可能性がある CreateUser オーバーロードに影響を与えるこのような Membership プロバイダー構成設定の 1 つが、requiresQuestionAndAnswer 設定です。 requiresQuestionAndAnswertrue (既定値) に設定されている場合は、新しいユーザー アカウントを作成するときに、セキュリティの質問と回答を指定する必要があります。 この情報は、後でユーザーが自分のパスワードをリセットまたは変更する必要がある場合に使用されます。 具体的には、その時点でセキュリティの質問が表示され、パスワードをリセットまたは変更するために正しい回答を入力する必要があります。 したがって、requiresQuestionAndAnswertrue に設定されている場合、最初の 2 つの CreateUser オーバーロードのいずれかを呼び出すと、セキュリティの質問と回答がないため、例外が発生します。 現在、アプリケーションはセキュリティの質問と回答を必要とするように構成されているため、ユーザーをプログラムで作成するときは、後者の 2 つのオーバーロードのいずれかを使用する必要があります。

CreateUser メソッドを使用して説明するために、ユーザーに自分の名前、パスワード、メール、定義済みのセキュリティの質問に対する回答を求めるユーザー インターフェイスを作成しましょう。 Membership フォルダーの CreatingUserAccounts.aspx ページを開き、次の Web コントロールを Content コントロールに追加します。

  • Username という名前のTextBox
  • TextMode プロパティが Password に設定されている Password という名前の TextBox
  • Email という名前の TextBox
  • Text プロパティがクリアされた SecurityQuestion という名前の Label
  • SecurityAnswer という名前の TextBox
  • Text プロパティが "Create the User Account" に設定されている CreateAccountButton という名前の Button
  • Text プロパティがクリアされた CreateAccountResults という名前の Label コントロール

この時点で、画面は図 6 に示すスクリーンショットのようになるはずです。

Add the Various Web Controls to the CreatingUserAccounts.aspx Page

図 6: さまざまな Web コントロールを CreatingUserAccounts.aspx ページに追加する (クリックするとフルサイズの画像が表示されます)

SecurityQuestion Label と SecurityAnswer TextBox は、定義済みのセキュリティの質問を表示し、ユーザーの回答を収集することを目的としています。 セキュリティの質問と回答の両方がユーザーごとに格納されるので、各ユーザーが独自のセキュリティの質問を定義できることに注意してください。 しかし、この例では、ユニバーサル セキュリティの質問、つまり、"What is your favorite color?" を使用することにしました。

この定義済みのセキュリティの質問を実装するには、passwordQuestion という名前のページの分離コード クラスに定数を追加し、セキュリティの質問を割り当てます。 その後、Page_Load イベント ハンドラーで、SecurityQuestion Label の Text プロパティにこの定数を割り当てます。

const string passwordQuestion = "What is your favorite color";
    
protected void Page_Load(object sender, EventArgs e)
{
     if (!Page.IsPostBack)
          SecurityQuestion.Text = passwordQuestion;
}

次に、CreateAccountButtonClick イベントのイベント ハンドラーを作成し、次のコードを追加します。

protected void CreateAccountButton_Click(object sender, EventArgs e)
{
     MembershipCreateStatus createStatus;
     MembershipUser newUser = Membership.CreateUser(Username.Text, Password.Text, Email.Text, passwordQuestion, SecurityAnswer.Text, true, out createStatus);
     switch (createStatus)
     {
          case MembershipCreateStatus.Success:
               CreateAccountResults.Text = "The user account was successfully created!";
               break;
          case MembershipCreateStatus.DuplicateUserName:
               CreateAccountResults.Text = "There already exists a user with this username.";
               break;

          case MembershipCreateStatus.DuplicateEmail:
               CreateAccountResults.Text = "There already exists a user with this email address.";
               break;
          case MembershipCreateStatus.InvalidEmail:
               CreateAccountResults.Text = "There email address you provided in invalid.";
               break;
          case MembershipCreateStatus.InvalidAnswer:
               CreateAccountResults.Text = "There security answer was invalid.";
               break;
          case MembershipCreateStatus.InvalidPassword:
               CreateAccountResults.Text = "The password you provided is invalid. It must be seven characters long and have at least one non-alphanumeric character.";

               break;
          default:
               CreateAccountResults.Text = "There was an unknown error; the user account was NOT created.";
               break;
     }
}

Click イベント ハンドラーでは、まず、MembershipCreateStatus 型の createStatus という名前の変数が定義されます。 MembershipCreateStatus は、CreateUser 操作の状態を示す列挙体です。 たとえば、ユーザー アカウントが正常に作成された場合、結果の MembershipCreateStatus インスタンスは Success の値に設定されます。その一方で、同じユーザー名を持つユーザーが既に存在するために操作が失敗した場合は、DuplicateUserName の値に設定されます。 使用する CreateUser オーバーロードでは、out パラメーターとしてメソッドに MembershipCreateStatus インスタンスを渡す必要があります。 このパラメーターは、CreateUser メソッド内の適切な値に設定されます。メソッド呼び出し後にその値を確認し、ユーザー アカウントが正常に作成されたかどうかを判断できます。

CreateUser を呼び出し、createStatus を渡した後、switch ステートメントを使用して、createStatus に割り当てられた値に応じて適切なメッセージを出力します。 図 7 は、新しいユーザーが正常に作成された場合の出力を示しています。 図 8 と図 9 は、ユーザー アカウントが作成されていない場合の出力を示しています。 図 8 では、訪問者は 5 文字のパスワードを入力しました。これは、Membership プロバイダーの構成設定に示されているパスワード強度要件を満たしていません。 図 9 では、訪問者は既存のユーザー名 (図 7 で作成されたもの) を使用してユーザー アカウントを作成しようとしています。

A New User Account is Successfully Created

図 7: 新しいユーザー アカウントが正常に作成された (クリックするとフルサイズの画像が表示されます)

The User Account is Not Created Because the Supplied Password is Too Weak

図 8: 指定されたパスワードが弱すぎるため、ユーザー アカウントが作成されない (クリックするとフルサイズの画像が表示されます)

The User Account is Not Created Because the Username is Already in Use

図 9: ユーザー名が既に使用されているため、ユーザー アカウントが作成されない (クリックするとフルサイズの画像が表示されます)

Note

最初の 2 つの CreateUser メソッド オーバーロード (どちらにも MembershipCreateStatus 型のパラメーターがない) のいずれかを使用する場合、成功または失敗を判断する方法を疑問に思うかもしれません。 これら最初の 2 つのオーバーロードでは、エラーが発生した場合に MembershipCreateUserException 例外がスローされます。これには、MembershipCreateStatus 型の StatusCode プロパティ が含まれます。

いくつかのユーザー アカウントを作成した後、SecurityTutorials.mdf データベースの aspnet_Usersaspnet_Membership テーブルの内容を一覧表示して、アカウントが作成されていることを確認します。 図 10 に示すように、CreatingUserAccounts.aspx ページで Tito と Bruce という 2 人のユーザーを追加しました。

There are Two Users in the Membership User Store: Tito and Bruce

図 10: Membership ユーザー ストアに Tito と Bruce という 2 人のユーザーがいる (クリックするとフルサイズの画像が表示されます)

Membership ユーザー ストアに Bruce と Tito のアカウント情報が含まれるようになりましたが、Bruce または Tito がサイトにログオンできるようにする機能はまだ実装していません。 現在、Login.aspx では、ハードコーディングされたユーザー名とパスワードのペアのセットに対してユーザーの資格情報が検証されます。Membership フレームワークに対して指定された資格情報は検証 "されません"。 ここでは、aspnet_Usersaspnet_Membership テーブルに新しいユーザー アカウントを表示すれば十分です。 次のチュートリアル「メンバーシップ ユーザー ストアに対してユーザー資格情報を確認する」では、Membership ストアに対して検証するようにログイン ページを更新します。

Note

SecurityTutorials.mdf データベースにユーザーが表示されない場合、Web アプリケーションで、既定の Membership プロバイダーである AspNetSqlMembershipProvider (ASPNETDB.mdf データベースをユーザー ストアとして使用) が使用されていることが原因である可能性があります。 これが問題かどうかを判断するには、ソリューション エクスプローラーの [更新] ボタンをクリックします。 ASPNETDB.mdf という名前のデータベースが App_Data フォルダーに追加されている場合は、これが問題です。 「SQL Server での Membership スキーマの作成」チュートリアルの手順 4 に戻り、Membership プロバイダーを適切に構成する方法に関する指示を確認してください。

ほとんどのユーザー アカウントの作成シナリオでは、訪問者にユーザー名、パスワード、メール、その他の重要な情報を入力するための何らかのインターフェイスが表示され、その時点で新しいアカウントが作成されます。 この手順では、このようなインターフェイスを手動で構築し、Membership.CreateUser メソッドを使用して、ユーザーの入力に基づいて新しいユーザー アカウントをプログラムで追加する方法を確認しました。 しかし、コードでは新しいユーザー アカウントが作成されただけです。 作成したばかりのユーザー アカウントでサイトにユーザーをログインさせる、または確認メールをユーザーに送信するなどのフォローアップ アクションは実行されませんでした。 これらの追加の手順では、Button の Click イベント ハンドラーに追加コードが必要になります。

ASP.NET には、新しいユーザー アカウントを作成するためのユーザー インターフェイスのレンダリングから、Membership フレームワークでのアカウントの作成やアカウント作成後のタスクの実行 (確認メールの送信や、作成したばかりのユーザーのサイトへのログ記録など) まで、ユーザー アカウント作成プロセスを処理するように設計された CreateUserWizard コントロールが付属しています。 CreateUserWizard コントロールの使用は、ツールボックスからページに CreateUserWizard コントロールをドラッグし、いくつかのプロパティを設定するのと同じくらい簡単です。 ほとんどの場合、コードを 1 行も記述する必要はありません。 このニフティ コントロールについては、手順 6 で詳しく調べます。

新しいユーザー アカウントが一般的なアカウントの作成 Web ページでのみ作成される場合、CreateUserWizard コントロールがニーズを満たす可能性が高いので、CreateUser メソッドを使用するコードを記述する必要はほとんどありません。 ただし、CreateUser メソッドは、高度にカスタマイズされたアカウントの作成ユーザー エクスペリエンスが必要なシナリオや、別のインターフェイスを使用してプログラムで新しいユーザー アカウントを作成する必要がある場合に便利です。 たとえば、ユーザーが他のアプリケーションのユーザー情報を含む XML ファイルをアップロードできるページがあるとします。 そのページでは、アップロードされた XML ファイルの内容が解析され、CreateUser メソッドを呼び出して XML で表される各ユーザーの新しいアカウントが作成される場合があります。

手順 6: CreateUserWizard コントロールを使用して新しいユーザーを作成する

ASP.NET には、多数の Login Web コントロールが付属しています。 これらのコントロールは、多くの一般的なユーザー アカウントとログイン関連のシナリオに役立ちます。 CreateUserWizard コントロール はそのようなコントロールの 1 つであり、Membership フレームワークに新しいユーザー アカウントを追加するためのユーザー インターフェイスを示すように設計されています。

他の多くの Login 関連 Web コントロールと同様に、CreateUserWizard はコードを 1 行も記述せずに使用できます。 Membership プロバイダーの構成設定に基づいて直感的にユーザー インターフェイスが提供され、ユーザーが必要な情報を入力して [ユーザーの作成] ボタンをクリックした後、Membership クラスの CreateUser メソッドが内部的に呼び出されます。 CreateUserWizard は非常にカスタマイズ可能なコントロールです。 アカウント作成プロセスのさまざまな段階で発生するイベントのホストがあります。 必要に応じてイベント ハンドラーを作成し、アカウント作成ワークフローにカスタム ロジックを挿入できます。 さらに、CreateUserWizard の外観は非常に柔軟です。 既定のインターフェイスの外観を定義するプロパティは多数あります。必要に応じて、コントロールをテンプレートに変換することも、追加のユーザー登録 "ステップ" を追加することもできます。

まず、CreateUserWizard コントロールの既定のインターフェイスの使用と動作について見ていきましょう。 その後、コントロールのプロパティとイベントを使用して外観をカスタマイズする方法を調べます。

CreateUserWizard の既定のインターフェイスと動作の確認

Membership フォルダーの CreatingUserAccounts.aspx ページに戻り、デザインまたは分割モードに切り替えて、ページの上部に CreateUserWizard コントロールを追加します。 CreateUserWizard コントロールは、ツールボックスの Login コントロール セクションの下に示されます。 コントロールを追加した後、その ID プロパティを RegisterUser に設定します。 図 11 のスクリーンショットに示すように、CreateUserWizard では、新しいユーザーのユーザー名、パスワード、メール アドレス、セキュリティの質問と回答のテキスト ボックスを含むインターフェイスがレンダリングされます。

The CreateUserWizard Control Renders a Generic Create User Interface

図 11: CreateUserWizard コントロールで汎用のユーザーの作成インターフェイスがレンダリングされる (クリックするとフルサイズの画像が表示されます)

少し時間を取って、CreateUserWizard コントロールによって生成された既定のユーザー インターフェイスと、手順 5 で作成したインターフェイスを比較しましょう。 まず、CreateUserWizard コントロールを使用すると、訪問者はセキュリティの質問と回答の両方を指定できます。一方、手動で作成したインターフェイスでは定義済みのセキュリティの質問が使用されています。 CreateUserWizard コントロールのインターフェイスには検証コントロールも含まれていますが、インターフェイスのフォーム フィールドに対する検証はまだ実装されていません。 CreateUserWizard コントロール インターフェイスには、[パスワードの確認入力] テキスト ボックスが含まれています ([パスワード] と [パスワードの比較] テキスト ボックスに入力されたテキストが等しいことを確かめるための CompareValidator と共に)。

興味深いのは、CreateUserWizard コントロールでは、ユーザー インターフェイスのレンダリング時に Membership プロバイダーの構成設定が参照されることです。 たとえば、セキュリティの質問と回答のテキスト ボックスは、requiresQuestionAndAnswer が True に設定されている場合にのみ表示されます。 同様に、CreateUserWizard では、確実にパスワードの強度要件が満たされるように自動的に RegularExpressionValidator コントロールが追加され、minRequiredPasswordLengthminRequiredNonalphanumericCharacterspasswordStrengthRegularExpression 構成設定に基づいて ErrorMessageValidationExpression プロパティが設定されます。

CreateUserWizard コントロールは、その名前が示すように、Wizard コントロールから派生します。 Wizard コントロールは、複数ステップのタスクを完了するためのインターフェイスを提供するように設計されています。 Wizard コントロールには任意の数の WizardSteps がある場合があり、それぞれがそのステップの HTML と Web コントロールを定義するテンプレートです。 Wizard コントロールでは最初に WizardStep と、ユーザーがあるステップから次のステップに進んだり、前のステップに戻ったりすることができるナビゲーション コントロールが表示されます。

図 11 の宣言型マークアップに示すように、CreateUserWizard コントロールの既定のインターフェイスには、次の 2 つの WizardSteps: が含まれます。

  • CreateUserWizardStep – 新しいユーザー アカウントを作成するための情報を収集するインターフェイスをレンダリングします。 これは図 11 に示されているステップです。
  • CompleteWizardStep – アカウントが正常に作成されたことを示すメッセージをレンダリングします。

CreateUserWizard の外観と動作は、これらのステップのいずれかをテンプレートに変換するか、独自の WizardSteps を追加することで変更できます。 登録インターフェイスに WizardStep を追加する方法については、「追加のユーザー情報を格納する」チュートリアルで確認します。

CreateUserWizard コントロールの動作を見てみましょう。 ブラウザーから CreatingUserAccounts.aspx ページにアクセスします。 まず、CreateUserWizard のインターフェイスに無効な値をいくつか入力します。 パスワード強度の要件に準拠していないパスワードを入力するか、[ユーザー名] テキストボックスを空のままにしてみます。 CreateUserWizard に適切なエラー メッセージが表示されます。 図 12 は、十分に強力なパスワードを使用してユーザーを作成しようとしたときの出力を示しています。

The CreateUserWizard Automatically Injects Validation Controls

図 12: CreateUserWizard で検証コントロールが自動的に挿入される (クリックするとフルサイズの画像が表示されます)

次に、CreateUserWizard に適切な値を入力し、[ユーザーの作成] ボタンをクリックします。 必須フィールドが入力されていて、パスワードの強度が十分であると仮定すると、CreateUserWizard では Membership フレームワークを使用して新しいユーザー アカウントが作成され、CompleteWizardStep のインターフェイスが表示されます (図 13 を参照)。 CreateUserWizard では、手順 5 で行ったように、バックグラウンドで Membership.CreateUser メソッドが呼び出されます。

A New User Account has Successfully Been Created

図 13: 新しいユーザー アカウントが正常に作成された (クリックするとフルサイズの画像が表示されます)

Note

図 13 に示すように、CompleteWizardStep のインターフェイスには [続行] ボタンが含まれています。 しかし、この時点でクリックするとポストバックが実行されるだけで、訪問者は同じページに残ります。 「CreateUserWizard の外観と動作をプロパティを使用してカスタマイズする」セクションでは、このボタンを使って訪問者を Default.aspx (またはその他のページ) に送る方法を確認します。

新しいユーザー アカウントを作成した後、Visual Studio に戻り、図 10 で行ったように aspnet_Usersaspnet_Membership テーブルを調べて、アカウントが正常に作成されたことを確認します。

CreateUserWizard の動作と外観をプロパティを使用してカスタマイズする

CreateUserWizard は、プロパティ、WizardSteps、イベント ハンドラーを使用して、さまざまな方法でカスタマイズできます。 このセクションでは、プロパティを使用してコントロールの外観をカスタマイズする方法を確認します。次のセクションでは、イベント ハンドラーを使用してコントロールの動作を拡張する方法を確認します。

CreateUserWizard コントロールの既定のユーザー インターフェイスに表示されるほとんどすべてのテキストは、多数のプロパティを使用してカスタマイズできます。 たとえば、テキスト ボックスの左側に表示される "ユーザー名"、"パスワード"、"パスワードの確認入力"、"メール"、"セキュリティの質問"、"セキュリティの回答" ラベルはそれぞれ、UserNameLabelTextPasswordLabelTextConfirmPasswordLabelTextEmailLabelTextQuestionLabelTextAnswerLabelText プロパティでカスタマイズできます。 同様に、CreateUserWizardStepCompleteWizardStep の [ユーザーの作成] と [続行] ボタンのテキストを指定するためのプロパティがあります。これらのボタンが Buttons、LinkButtons、または ImageButtons としてレンダリングされる場合も同様です。

色、罫線、フォント、およびその他のビジュアル要素は、スタイル プロパティのホストを通じて構成できます。 CreateUserWizard コントロール自体には、共通の Web コントロール スタイル プロパティ (BackColorBorderStyleCssClassFont など) があり、CreateUserWizard のインターフェイスの特定のセクションの外観を定義するためのスタイル プロパティは多数あります。 たとえば、TextBoxStyle プロパティでは CreateUserWizardStep のテキスト ボックスのスタイルが定義されますが、TitleTextStyle プロパティではタイトルのスタイル ("新しいアカウントにサインアップ") が定義されます。

外観関連のプロパティに加え、CreateUserWizard コントロールの動作に影響するプロパティは多数あります。 DisplayCancelButton プロパティを True に設定すると、[ユーザーの作成] ボタンの横に [キャンセル] ボタンが表示されます (既定値は False です)。 [キャンセル] ボタンを表示する場合は、必ず、CancelDestinationPageUrl プロパティも設定してください。これにより、[キャンセル] をクリックした後にユーザーが送られるページが指定されます。 前のセクションで説明したように、CompleteWizardStep のインターフェイスの [続行] ボタンをクリックするとポストバックが発生しますが、訪問者は同じページに残ります。 [続行] ボタンをクリックした後、訪問者を他のページに送る場合は、ContinueDestinationPageUrl プロパティで URL を指定するだけです。

RegisterUser CreateUserWizard コントロールを更新して、[キャンセル] ボタンを表示し、[キャンセル] または [続行] ボタンがクリックされたときに訪問者を Default.aspx に送ってみましょう。 これを実現するには、DisplayCancelButton プロパティを True に設定し、CancelDestinationPageUrlContinueDestinationPageUrl プロパティの両方を "~/Default.aspx" に設定します。 図 14 は、ブラウザーで表示されたときの更新された CreateUserWizard を示しています。

The CreateUserWizardStep Includes a Cancel Button

図 14: CreateUserWizardStep に [キャンセル] ボタンが含まれている (クリックするとフルサイズの画像が表示されます)

訪問者がユーザー名、パスワード、メール アドレス、セキュリティの質問と回答を入力し、[ユーザーの作成] をクリックすると、新しいユーザー アカウントが作成され、その新しく作成されたユーザーとして訪問者がログインします。 ページにアクセスするユーザーが自分で新しいアカウントを作成していると仮定すると、これは望ましい動作である可能性があります。 しかし、管理者に新しいユーザー アカウントの追加を許可する必要がある場合があります。 その場合、ユーザー アカウントは作成されますが、管理者は (新しく作成されたアカウントとしてではなく) 管理者としてログインしたままになります。 この動作は、ブール値の LoginCreatedUser プロパティを使用して変更できます。

Membership フレームワークのユーザー アカウントには、承認されたフラグが含まれています。承認されていないユーザーは、サイトにログインできません。 既定では、新しく作成されたアカウントは承認済みとしてマークされ、ユーザーはすぐにサイトにログインできます。 しかし、新しいユーザー アカウントが未承認としてマークされている可能性があります。 新しいユーザーがログインする前に管理者が手動でそのユーザーを承認するようにしたい場合や、ユーザーにログオンを許可する前に、サインアップ時に入力されたメール アドレスが有効であることを確認したい場合があります。 いずれの場合も、CreateUserWizard コントロールの DisableCreatedUser プロパティを True (既定値は False) に設定することで、新しく作成されたユーザー アカウントを未承認としてマークすることができます。

その他の動作に関連する注意事項のプロパティには、AutoGeneratePasswordMailDefinition が含まれます。 AutoGeneratePassword プロパティが True に設定されている場合、CreateUserWizardStep には [パスワード] と [パスワードの確認入力] テキスト ボックスは表示されません。代わりに、新しく作成されたユーザーのパスワードが、Membership クラスの GeneratePassword メソッドを使用して自動的に生成されます。 GeneratePassword メソッドでは、指定された長さの、構成されたパスワード強度要件を満たすのに十分な数の英数字以外の文字を含むパスワードが構築されます。

MailDefinition プロパティは、アカウントの作成プロセス中に指定されたメール アドレスにメールを送信する場合に便利です。 MailDefinition プロパティには、構築されたメール メッセージに関する情報を定義するための一連のサブプロパティが含まれています。 これらのサブプロパティには、SubjectPriorityIsBodyHtmlFromCCBodyFileName などのオプションが含まれています。 BodyFileName プロパティは、メール メッセージの本文を含むテキストまたは HTML ファイルを指します。 本文では、<%UserName%><%Password%> の 2 つの定義済みプレースホルダーがサポートされています。 これらのプレースホルダー (BodyFileName ファイルに存在する場合) は、作成したばかりのユーザーの名前とパスワードに置き換えられます。

Note

CreateUserWizard コントロールの MailDefinition プロパティでは、新しいアカウントの作成時に送信されるメール メッセージに関する詳細のみが指定されます。 メール メッセージの実際の送信方法に関する詳細 (つまり、SMTP サーバーとメール ドロップ ディレクトリのどちらが使用されているかや認証情報など) は含まれません。 これらの詳細は、Web.config<system.net> セクションで定義する必要があります。 これらの構成設定と、一般的な ASP.NET 2.0 からのメール送信の詳細については、SystemNetMail.com の FAQ と、ASP.NET 2.0 でのメール送信に関する記事を参照してください。

イベント ハンドラーを使用した CreateUserWizard の動作の拡張

CreateUserWizard コントロールでは、ワークフロー中に多数のイベントが発生します。 たとえば、訪問者がユーザー名、パスワード、およびその他の関連情報を入力し、[ユーザーの作成] ボタンをクリックすると、CreateUserWizard コントロールでは CreatingUser イベントが発生します。 作成プロセス中に問題が発生した場合、CreateUserError イベントが発生します。ただし、ユーザーが正常に作成された場合は、CreatedUser イベントが発生します。 さらに発生する CreateUserWizard コントロール イベントがありますが、それら 3 つは最も密接に関連するものです。

特定のシナリオでは、CreateUserWizard ワークフローを利用する必要がある場合があります。これは、適切なイベントのイベント ハンドラーを作成することで行うことができます。 これを説明するために、RegisterUser CreateUserWizard コントロールを拡張し、ユーザー名とパスワードのカスタム検証を含めましょう。 具体的には、CreateUserWizard を拡張し、ユーザー名の先頭や末尾にスペースを含めることができず、ユーザー名をパスワードのどこにも表示できないようにしましょう。 要するに、"Scott" のようなユーザー名を作成したり、"Scott" や "Scott.1234" のようなユーザー名とパスワードの組み合わせを作成できないようにします。

これを実現するために、追加の検証チェックを実行する CreatingUser イベントのイベント ハンドラーを作成します。 指定されたデータが無効な場合は、作成プロセスを取り消す必要があります。 また、Label Web コントロールをページに追加して、ユーザー名またはパスワードが無効であることを説明するメッセージを表示する必要があります。 まず、CreateUserWizard コントロールの下に Label コントロールを追加し、その ID プロパティを InvalidUserNameOrPasswordMessage に設定し、ForeColor プロパティを Red に設定します。 その Text プロパティをクリアし、EnableViewStateVisible プロパティを False に設定します。

<asp:Label runat="server" id="InvalidUserNameOrPasswordMessage"
     Visible="false" ForeColor="Red" EnableViewState="false">

</asp:Label>

次に、CreateUserWizard コントロールの CreatingUser イベントのイベント ハンドラーを作成します。 イベント ハンドラーを作成するには、デザイナーでコントロールを選択し、プロパティ ウィンドウに移動します。 そこから、稲妻アイコンをクリックし、適切なイベントをダブルクリックしてイベント ハンドラーを作成します。

CreatingUser イベント ハンドラーに次のコードを追加します。

protected void RegisterUser_CreatingUser(object sender, LoginCancelEventArgs e)
{
     string trimmedUserName = RegisterUser.UserName.Trim();
     if (RegisterUser.UserName.Length != trimmedUserName.Length)
     {
          // Show the error message
          InvalidUserNameOrPasswordMessage.Text = "The username cannot contain leading or trailing spaces.";
          InvalidUserNameOrPasswordMessage.Visible = true;

          // Cancel the create user workflow
          e.Cancel = true;
     }
     else
     {
          // Username is valid, make sure that the password does not contain the username

          if (RegisterUser.Password.IndexOf(RegisterUser.UserName, StringComparison.OrdinalIgnoreCase) >= 0)
          {
               // Show the error message
               InvalidUserNameOrPasswordMessage.Text = "The username may not appear anywhere in the password.";
               InvalidUserNameOrPasswordMessage.Visible = true;
               // Cancel the create user workflow
               e.Cancel = true;
          }
     }
}

CreateUserWizard コントロールに入力されたユーザー名とパスワードは、それぞれ UserNamePassword プロパティを介して使用できることに注意してください。 上記のイベント ハンドラーでこれらのプロパティを使用して、指定されたユーザー名の先頭または末尾にスペースが含まれているかどうか、およびユーザー名がパスワード内で見つかったかどうかを判断します。 これらの条件のいずれかが満たされると、エラー メッセージが InvalidUserNameOrPasswordMessage Label に表示され、イベント ハンドラーの e.Cancel プロパティが true に設定されます。 e.Canceltrue に設定されている場合、CreateUserWizard ではワークフローが省略され、ユーザー アカウントの作成プロセスが実質的に取り消されます。

図 15 は、ユーザーが先頭にスペースを含むユーザー名を入力したときの CreatingUserAccounts.aspx のスクリーンショットを示しています。

Usernames with Leading or Trailing Spaces are not Permitted

図 15: 先頭または末尾にスペースを含むユーザー名は許可されない (クリックするとフルサイズの画像が表示されます)

Note

CreateUserWizard コントロールの CreatedUser イベントの使用例については、「追加のユーザー情報を格納する」チュートリアルで確認します。

まとめ

Membership クラスの CreateUser メソッドでは、Membership フレームワークに新しいユーザー アカウントが作成されます。 これは、構成された Membership プロバイダーに呼び出しを委任することで行われます。 SqlMembershipProvider の場合、CreateUser メソッドでは、aspnet_Usersaspnet_Membership データベース テーブルにレコードが追加されます。

新しいユーザー アカウントはプログラムで作成できますが (手順 5 で確認したように)、CreateUserWizard コントロールを使用する方が高速で簡単です。 このコントロールでは、ユーザー情報を収集し、Membership フレームワークで新しいユーザーを作成するためのマルチステップ ユーザー インターフェイスがレンダリングされます。 このコントロールでは、内部的に、手順 5 で確認したのと同じ Membership.CreateUser メソッドが使用されますが、ユーザー インターフェイス、検証コントロールが作成され、コードを 1 行も記述することなく、ユーザー アカウント作成エラーに応答します。

この時点で、新しいユーザー アカウントを作成する機能の準備ができました。 しかし、ログイン ページでは、2 番目のチュートリアルで指定したハードコーディングされた資格情報に対して引き続き検証が行われます。 次のチュートリアルでは、Membership フレームワークに対してユーザーが指定した資格情報を検証するために Login.aspx を更新します。

プログラミングに満足!

もっと読む

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

作成者について

複数の 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 でした。 今後の MSDN の記事を確認することに関心がありますか? その場合は、mitchell@4GuysFromRolla.com までご一報ください。