ユーザー アカウントを作成する (C#)
Note
この記事を作成した後で、ASP.NET メンバーシップ プロバイダーよりも ASP.NET Identity のほうが適切になりました。 この記事の作成時点で紹介されている Membership プロバイダーではなく、ASP.NET Identity プラットフォームを使うようにアプリを更新することを強くお勧めします。 ASP.NET メンバーシップ システムと比べると、ASP.NET Identity には次のような多くの利点があります。
- パフォーマンスの向上
- 向上した拡張性とテストの容易性
- OAuth、OpenID Connect、2 要素認証のサポート
- クレームベースの ID のサポート
- ASP.Net Core との相互運用性の向上
このチュートリアルでは、メンバーシップ フレームワークを使って (SqlMembershipProvider を使用) 新しいユーザー アカウントを作成する方法について確認します。 プログラムと ASP.NET の組み込みの CreateUserWizard コントロールを使用して、新しいユーザーを作成する方法を確認します。
はじめに
前のチュートリアルでは、アプリケーション サービス スキーマをデータベースにインストールしました。これにより、SqlMembershipProvider
と SqlRoleProvider
に必要なテーブル、ビュー、ストアド プロシージャが追加されました。 これにより、このシリーズのチュートリアルの残りの部分に必要なインフラストラクチャが作成されました。 このチュートリアルでは、メンバーシップ フレームワークを使って (SqlMembershipProvider
を使用) 新しいユーザー アカウントを作成する方法について確認します。 プログラムと ASP.NET の組み込みの CreateUserWizard コントロールを使用して、新しいユーザーを作成する方法を確認します。
新しいユーザー アカウントを作成する方法を学習するだけでなく、「フォーム認証の概要」チュートリアルで最初に作成したデモ Web サイトを更新してから、「フォーム認証構成と高度なトピック」チュートリアルで拡張する必要もあります。 デモ Web アプリケーションには、ハードコーディングされたユーザー名とパスワードのペアに対してユーザーの資格情報を検証するログイン ページがあります。 さらに、Global.asax
には、認証されたユーザーのカスタム IPrincipal
および IIdentity
オブジェクトを作成するコードが含まれています。 メンバーシップ フレームワークに対してユーザーの資格情報を検証し、カスタム プリンシパルと ID ロジックを削除するように、ログイン ページを更新します。
それでは始めましょう。
フォーム認証とメンバーシップのチェックリスト
メンバーシップ フレームワークで作業を開始する前に、少し時間を取って、これまでに行った重要な手順を確認しましょう。 フォームベース認証シナリオでメンバーシップ フレームワークを SqlMembershipProvider
と共に使用する場合は、Web アプリケーションにメンバーシップ機能を実装する前に、次の手順を行う必要があります。
- フォームベース認証を有効にします。 「フォーム認証の概要」で説明したように、フォーム認証は、
Web.config
を編集し、<authentication>
要素のmode
属性をForms
に設定することで有効になります。 フォーム認証が有効になっている場合、各受信要求では、要求元を識別するフォーム認証チケット (存在する場合) が確認されます。 - アプリケーション サービス スキーマを適切なデータベースに追加します。
SqlMembershipProvider
を使用する場合は、アプリケーション サービス スキーマをデータベースにインストールする必要があります。 通常、このスキーマは、アプリケーションのデータ モデルを保持する同じデータベースに追加されます。 「SQL Server でのメンバーシップ スキーマの作成」チュートリアルでは、aspnet_regsql.exe
ツールを使用してこれを行う方法について確認しました。 - 手順 2 のデータベースを参照するように Web アプリケーションの設定をカスタマイズします。 「SQL Server でのメンバーシップ スキーマの作成」チュートリアルでは、
SqlMembershipProvider
が手順 2 で選択されたデータベースを使用するように Web アプリケーションを構成する 2 つの方法を示しました。つまり、LocalSqlServer
接続文字列名を変更する方法と、メンバーシップ フレームワーク プロバイダーのリストに新しい登録済みプロバイダーを追加し、手順 2 のデータベースを使用するように新しいプロバイダーをカスタマイズする方法です。
SqlMembershipProvider
とフォームベース認証を使用する Web アプリケーションを構築する場合は、Membership
クラスまたは ASP.NET Login Web コントロールを使う前に、次の 3 つの手順を行う必要があります。 前のチュートリアルでこれらの手順を既に行っているため、メンバーシップ フレームワークの使用を開始する準備はできています。
手順 1: 新しい ASP.NET ページを追加する
これと次の 3 つのチュートリアルでは、メンバーシップ関連のさまざまな機能について確認します。 これらのチュートリアル全体で確認するトピックを実装するには、一連の ASP.NET ページが必要です。 これらのページを作成し、サイト マップ ファイル (Web.sitemap)
を作成してみましょう。
まず、プロジェクトに Membership
という名前の新しいフォルダーを作成します。 次に、5 つの新しい ASP.NET ページを Membership
フォルダーに追加し、各ページを Site.master
マスター ページにリンクします。 ページに次の名前を付けます。
CreatingUserAccounts.aspx
UserBasedAuthorization.aspx
EnhancedCreateUserWizard.aspx
AdditionalUserInfo.aspx
Guestbook.aspx
この時点で、プロジェクトのソリューション エクスプローラーは、図 1 に示すスクリーンショットのようになります。
図 1: Membership
フォルダーに 5 つの新しいページが追加された (クリックするとフルサイズの画像を表示されます)
この時点で、各ページには、マスター ページの ContentPlaceHolders ごとに 1 つずつ、MainContent
と LoginContent
という 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
クラス) を使用してアクセスできます。 組み込みのナビゲーション Web コントロールには、Menu コントロール、TreeView コントロール、SiteMapPath コントロールが含まれます。
メンバーシップ とロール フレームワークと同様に、サイト マップ フレームワークはプロバイダー モデルの上に構築されます。 サイト マップ プロバイダー クラスのジョブは、XML ファイルやデータベース テーブルなどの永続的なデータ ストアから、SiteMap
クラスによって使用されるインメモリ構造を生成することです。 .NET Framework には、XML ファイルからサイト マップ データを読み取る既定のサイト マップ プロバイダー (XmlSiteMapProvider
) が付属しています。これは、このチュートリアルで使用するプロバイダーです。 いくつかの代替サイト マップ プロバイダーの実装については、このチュートリアルの最後にある「参考資料」セクションを参照してください。
既定のサイト マップ プロバイダーでは、ルート ディレクトリが存在する Web.sitemap
という名前の適切な形式の XML ファイルが必要です。 この既定のプロバイダーを使用しているため、このようなファイルを追加し、適切な XML 形式でサイト マップの構造を定義する必要があります。 ファイルを追加するには、ソリューション エクスプローラーでプロジェクト名を右クリックし、[新しい項目の追加] を選択します。 ダイアログ ボックスから、Web.sitemap
という名前のサイト マップ型のファイルを追加することを選択します。
図 2: プロジェクトのルート ディレクトリに Web.sitemap
という名前のファイルを追加する (クリックするとフルサイズの画像が表示されます)
XML サイト マップ ファイルでは、Web サイトの構造が階層として定義されます。 この階層関係は、<siteMapNode>
要素の先祖を介して XML ファイルでモデル化されます。 Web.sitemap
は、<siteMapNode>
子が 1 つだけの <siteMap>
親ノードで始まる必要があります。 この最上位の <siteMapNode>
要素は階層のルートを表し、任意の数の子孫ノードを持つことができます。 各 <siteMapNode>
要素には title
属性を含める必要があり、必要に応じて、特に url
や description
属性を含めることができます。空でない各 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 に示されている階層が定義されています。
図 3: サイト マップが階層ナビゲーション構造を表している (クリックするとフルサイズ画像が表示されます)
手順 3: ナビゲーション ユーザー インターフェイスを含むようにマスター ページを更新する
ASP.NET には、ユーザー インターフェイスを設計するためのナビゲーション関連の Web コントロールが多数含まれています。 これには、Menu、TreeView、および SiteMapPath コントロールが含まれます。 Menu と TreeView コントロールでは、それぞれメニューまたはツリーにサイト マップ構造がレンダリングされます。一方、SiteMapPath では、アクセスされている現在のノードとその先祖を示す階層リンクが表示されます。 サイト マップ データは、SiteMapDataSource を使用して他のデータ Web コントロールにバインドでき、SiteMap
クラスを介してプログラムでアクセスできます。
サイト マップ フレームワークとナビゲーション コントロールの詳細な説明は、このチュートリアル シリーズの範囲外であるため、独自のナビゲーション ユーザー インターフェイスの作成に時間を費やすのではなく、図 4 に示すように、ナビゲーション リンクの深さ 2 の箇条書きを表示するために Repeater コントロールを使用する、「ASP.NET 2.0 でのデータ操作」チュートリアル シリーズで使用するものを代わりに借用しましょう。
左側の列にリンクの 2 レベル リストを追加する
このインターフェイスを作成するには、次の宣言型マークアップを 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
で定義されているカスケード スタイル シートの規則の役割は、見た目が美しいレイアウトにすることです。 上記のマークアップのしくみの詳細については、「マスター ページとサイト ナビゲーション」チュートリアルを参照してください。
図 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 の出力が示されています。
図 5: 階層リンクには、現在のページとその先祖がサイト マップに表示される (クリックするとフルサイズの画像が表示されます)
手順 4: カスタム プリンシパルと ID ロジックを削除する
カスタム プリンシパルおよび ID オブジェクトは、認証されたユーザーに関連付けることができます。 これを実現するには、FormsAuthenticationModule
でユーザーが認証された後に発生する、アプリケーションの PostAuthenticateRequest
イベントの Global.asax
にイベント ハンドラーを作成します。 このイベント ハンドラーでは、FormsAuthenticationModule
によって追加された GenericPrincipal
と FormsIdentity
オブジェクトを、そのチュートリアルで作成した CustomPrincipal
と CustomIdentity
オブジェクトに置き換えました。
カスタム プリンシパルおよび ID オブジェクトは特定のシナリオで役立ちますが、ほとんどの場合、GenericPrincipal
と FormsIdentity
オブジェクトで十分です。 したがって、既定の動作に戻す価値があると考えます。 この変更を行うには、PostAuthenticateRequest
イベント ハンドラーを削除またはコメント アウトするか、Global.asax
ファイルを完全に削除します。
手順 5: プログラムによる新しいユーザーの作成
メンバーシップ フレームワークを使って新しいユーザー アカウントを作成するには、Membership
クラスの CreateUser
メソッドを使用します。 このメソッドには、ユーザー名、パスワード、その他のユーザー関連フィールドの入力パラメーターがあります。 呼び出し時に、新しいユーザー アカウントの作成が構成済みのメンバーシップ プロバイダーに委任され、作成したばかりのユーザー アカウントを表す MembershipUser
オブジェクトが返されます。
CreateUser
メソッドには、それぞれ異なる数の入力パラメーターを受け入れる 4 つのオーバーロードがあります。
CreateUser(username, password)
CreateUser(username, password, email)
CreateUser(username, password, email, passwordQuestion, passwordAnswer, isApproved, MembershipCreateStatus)
CreateUser(username, password, email, passwordQuestion, passwordAnswer, isApproved, providerUserKey, MembershipCreateStatus)
これら 4 つのオーバーロードは、収集される情報の量によって異なります。 たとえば、最初のオーバーロードでは、新しいユーザー アカウントのユーザー名とパスワードだけが必要ですが、2 つ目のオーバーロードではユーザーのメール アドレスも必要です。
これらのオーバーロードが存在するのは、新しいユーザー アカウントの作成に必要な情報がメンバーシップ プロバイダーの構成設定によって異なるためです。 「SQL Server でのメンバーシップ スキーマの作成」チュートリアルで、Web.config
でのメンバーシップ プロバイダーの構成設定の指定について確認しました。 表 2 には、構成設定の完全なリストが含まれていました。
使用される可能性がある CreateUser
オーバーロードに影響を与えるこのようなメンバーシップ プロバイダー構成設定の 1 つが、requiresQuestionAndAnswer
設定です。 requiresQuestionAndAnswer
が true
(既定値) に設定されている場合は、新しいユーザー アカウントを作成するときに、セキュリティの質問と回答を指定する必要があります。 この情報は、後でユーザーが自分のパスワードをリセットまたは変更する必要がある場合に使用されます。 具体的には、その時点でセキュリティの質問が表示され、パスワードをリセットまたは変更するために正しい回答を入力する必要があります。 したがって、requiresQuestionAndAnswer
が true
に設定されている場合、最初の 2 つの CreateUser
オーバーロードのいずれかを呼び出すと、セキュリティの質問と回答がないため、例外が発生します。 現在、アプリケーションはセキュリティの質問と回答を必要とするように構成されているため、ユーザーをプログラムで作成するときは、後者の 2 つのオーバーロードのいずれかを使用する必要があります。
CreateUser
メソッドを使用して説明するために、ユーザーに自分の名前、パスワード、メール、定義済みのセキュリティの質問に対する回答を求めるユーザー インターフェイスを作成しましょう。 Membership
フォルダーの CreatingUserAccounts.aspx
ページを開き、次の Web コントロールを Content コントロールに追加します。
Username
という名前のTextBoxTextMode
プロパティがPassword
に設定されているPassword
という名前の TextBoxEmail
という名前の TextBoxText
プロパティがクリアされたSecurityQuestion
という名前の LabelSecurityAnswer
という名前の TextBox- Text プロパティが "Create the User Account" に設定されている
CreateAccountButton
という名前の Button Text
プロパティがクリアされたCreateAccountResults
という名前の Label コントロール
この時点で、画面は図 6 に示すスクリーンショットのようになるはずです。
図 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;
}
次に、CreateAccountButton
の Click
イベントのイベント ハンドラーを作成し、次のコードを追加します。
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 文字のパスワードを入力しました。これは、メンバーシップ プロバイダーの構成設定に示されているパスワード強度要件を満たしていません。 図 9 では、訪問者は既存のユーザー名 (図 7 で作成されたもの) を使用してユーザー アカウントを作成しようとしています。
図 7: 新しいユーザー アカウントが正常に作成された (クリックするとフルサイズの画像が表示されます)
図 8: 指定されたパスワードが弱すぎるため、ユーザー アカウントが作成されない (クリックするとフルサイズの画像が表示されます)
図 9: ユーザー名が既に使用されているため、ユーザー アカウントが作成されない (クリックするとフルサイズの画像が表示されます)
Note
最初の 2 つの CreateUser
メソッド オーバーロード (どちらにも MembershipCreateStatus
型のパラメーターがない) のいずれかを使用する場合、成功または失敗を判断する方法を疑問に思うかもしれません。 これら最初の 2 つのオーバーロードでは、エラーが発生した場合に MembershipCreateUserException
例外がスローされます。これには、MembershipCreateStatus
型の StatusCode
プロパティが含まれます。
いくつかのユーザー アカウントを作成した後、SecurityTutorials.mdf
データベースの aspnet_Users
と aspnet_Membership
テーブルの内容を一覧表示して、アカウントが作成されていることを確認します。 図 10 に示すように、CreatingUserAccounts.aspx
ページで Tito と Bruce という 2 人のユーザーを追加しました。
図 10: メンバーシップ ユーザー ストアに Tito と Bruce という 2 人のユーザーがいる (クリックするとフルサイズの画像が表示されます)
Membership ユーザー ストアに Bruce と Tito のアカウント情報が含まれるようになりましたが、Bruce または Tito がサイトにログオンできるようにする機能はまだ実装していません。 現在、Login.aspx
では、ハードコーディングされたユーザー名とパスワードのペアのセットに対してユーザーの資格情報が検証されます。Membership フレームワークに対して指定された資格情報は検証 "されません"。 ここでは、aspnet_Users
と aspnet_Membership
テーブルに新しいユーザー アカウントを表示すれば十分です。 次のチュートリアル「メンバーシップ ユーザー ストアに対してユーザー資格情報を確認する」では、メンバーシップ ストアに対して検証するようにログイン ページを更新します。
Note
SecurityTutorials.mdf
データベースにユーザーが表示されない場合、Web アプリケーションで、既定のメンバーシップ プロバイダーである AspNetSqlMembershipProvider
(ASPNETDB.mdf
データベースをユーザー ストアとして使用) が使用されていることが原因である可能性があります。 これが問題かどうかを判断するには、ソリューション エクスプローラーの [更新] ボタンをクリックします。 ASPNETDB.mdf
という名前のデータベースが App_Data
フォルダーに追加されている場合は、これが問題です。 「SQL Server でのメンバーシップ スキーマの作成」チュートリアルの手順 4 に戻り、メンバーシップ プロバイダーを適切に構成する方法に関する指示を確認してください。
ほとんどのユーザー アカウントの作成シナリオでは、訪問者にユーザー名、パスワード、メール、その他の重要な情報を入力するための何らかのインターフェイスが表示され、その時点で新しいアカウントが作成されます。 この手順では、このようなインターフェイスを手動で構築し、Membership.CreateUser
メソッドを使用して、ユーザーの入力に基づいて新しいユーザー アカウントをプログラムで追加する方法を確認しました。 しかし、コードでは新しいユーザー アカウントが作成されただけです。 作成したばかりのユーザー アカウントでサイトにユーザーをログインさせる、または確認メールをユーザーに送信するなどのフォローアップ アクションは実行されませんでした。 これらの追加の手順では、Button の Click
イベント ハンドラーに追加コードが必要になります。
ASP.NET には、新しいユーザー アカウントを作成するためのユーザー インターフェイスのレンダリングから、メンバーシップ フレームワークでのアカウントの作成やアカウント作成後のタスクの実行 (確認メールの送信や、作成したばかりのユーザーのサイトへのログ記録など) まで、ユーザー アカウント作成プロセスを処理するように設計された CreateUserWizard コントロールが付属しています。 CreateUserWizard コントロールの使用は、ツールボックスからページに CreateUserWizard コントロールをドラッグし、いくつかのプロパティを設定するだけで済むため、簡単です。 ほとんどの場合、コードを 1 行も記述する必要はありません。 このニフティ コントロールについては、手順 6 で確認します。
新しいユーザー アカウントが一般的なアカウントの作成 Web ページでのみ作成される場合、CreateUserWizard コントロールがニーズを満たす可能性が高いので、CreateUser
メソッドを使用するコードを記述する必要はほとんどありません。 ただし、CreateUser
メソッドは、高度にカスタマイズされたアカウントの作成ユーザー エクスペリエンスが必要なシナリオや、別のインターフェイスを使用してプログラムで新しいユーザー アカウントを作成する必要がある場合に便利です。 たとえば、ユーザーが他のアプリケーションのユーザー情報を含む XML ファイルをアップロードできるページがあるとします。 そのページでは、アップロードされた XML ファイルの内容が解析され、CreateUser
メソッドを呼び出して XML で表される各ユーザーの新しいアカウントが作成される場合があります。
手順 6: CreateUserWizard コントロールを使用して新しいユーザーを作成する
ASP.NET には、多数の Login Web コントロールが付属しています。 これらのコントロールは、多くの一般的なユーザー アカウントとログイン関連のシナリオに役立ちます。 CreateUserWizard コントロール はそのようなコントロールの 1 つであり、メンバーシップ フレームワークに新しいユーザー アカウントを追加するためのユーザー インターフェイスを示すように設計されています。
他の多くの Login 関連 Web コントロールと同様に、CreateUserWizard はコードを 1 行も記述せずに使用できます。 Membership プロバイダーの構成設定に基づいて直感的にユーザー インターフェイスが提供され、ユーザーが必要な情報を入力して [ユーザーの作成] ボタンをクリックした後、Membership
クラスの CreateUser
メソッドが内部的に呼び出されます。 CreateUserWizard は非常にカスタマイズ可能なコントロールです。 アカウント作成プロセスのさまざまな段階で発生する多数のイベントがあります。 必要に応じてイベント ハンドラーを作成し、アカウント作成ワークフローにカスタム ロジックを挿入できます。 さらに、CreateUserWizard の外観は非常に柔軟です。 既定のインターフェイスの外観を定義するプロパティは多数あります。必要に応じて、コントロールをテンプレートに変換することも、追加のユーザー登録 "ステップ" を追加することもできます。
まず、CreateUserWizard コントロールの既定のインターフェイスの使用と動作について見ていきましょう。 その後、コントロールのプロパティとイベントを使用して外観をカスタマイズする方法を調べます。
CreateUserWizard の既定のインターフェイスと動作の確認
Membership
フォルダーの CreatingUserAccounts.aspx
ページに戻り、デザインまたは分割モードに切り替えて、ページの上部に CreateUserWizard コントロールを追加します。 CreateUserWizard コントロールは、ツールボックスの Login コントロール セクションの下に示されます。 コントロールを追加した後、その ID
プロパティを RegisterUser
に設定します。 図 11 のスクリーンショットに示すように、CreateUserWizard では、新しいユーザーのユーザー名、パスワード、メール アドレス、セキュリティの質問と回答のテキスト ボックスを含むインターフェイスがレンダリングされます。
図 11: CreateUserWizard コントロールで汎用のユーザーの作成インターフェイスがレンダリングされる (クリックするとフルサイズの画像が表示されます)
少し時間を取って、CreateUserWizard コントロールによって生成された既定のユーザー インターフェイスと、手順 5 で作成したインターフェイスを比較しましょう。 まず、CreateUserWizard コントロールを使用すると、訪問者はセキュリティの質問と回答の両方を指定できます。一方、手動で作成したインターフェイスでは定義済みのセキュリティの質問が使用されています。 CreateUserWizard コントロールのインターフェイスには検証コントロールも含まれていますが、インターフェイスのフォーム フィールドに対する検証はまだ実装されていません。 CreateUserWizard コントロール インターフェイスには、[パスワードの確認入力] テキスト ボックスが含まれています ([パスワード] と [パスワードの比較] テキスト ボックスに入力されたテキストが等しいことを確かめるための CompareValidator と共に)。
興味深いのは、CreateUserWizard コントロールでは、ユーザー インターフェイスのレンダリング時に Membership プロバイダーの構成設定が参照されることです。 たとえば、セキュリティの質問と回答のテキストボックスは、requiresQuestionAndAnswer
が True に設定されている場合にのみ表示されます。 同様に、CreateUserWizard では、確実にパスワードの強度要件が満たされるように自動的に RegularExpressionValidator コントロールが追加され、minRequiredPasswordLength
、minRequiredNonalphanumericCharacters
、passwordStrengthRegularExpression
構成設定に基づいて ErrorMessage
と ValidationExpression
プロパティが設定されます。
CreateUserWizard コントロールは、その名前が示すように、ウィザード コントロールから派生します。 Wizard コントロールは、複数ステップのタスクを完了するためのインターフェイスを提供するように設計されています。 Wizard コントロールには任意の数の WizardSteps
がある場合があり、それぞれがそのステップの HTML と Web コントロールを定義するテンプレートです。 Wizard コントロールでは最初に WizardStep
と、ユーザーがあるステップから次のステップに進んだり、前のステップに戻ったりすることができるナビゲーション コントロールが表示されます。
図 11 の宣言型マークアップに示すように、CreateUserWizard コントロールの既定のインターフェイスには、次の 2 つの WizardSteps:
が含まれます。
CreateUserWizardStep
– 新しいユーザー アカウントを作成するための情報を収集するインターフェイスをレンダリングします。 これは図 11 に示されているステップです。CompleteWizardStep
– アカウントが正常に作成されたことを示すメッセージをレンダリングします。
CreateUserWizard の外観と動作は、これらのステップのいずれかをテンプレートに変換するか、独自の WizardSteps
を追加することで変更できます。 登録インターフェイスに WizardStep
を追加する方法については、「追加のユーザー情報を格納する」チュートリアルで確認します。
CreateUserWizard コントロールの動作を見てみましょう。 ブラウザーから CreatingUserAccounts.aspx
ページにアクセスします。 まず、CreateUserWizard のインターフェイスに無効な値をいくつか入力します。 パスワード強度の要件に準拠していないパスワードを入力するか、[ユーザー名] テキストボックスを空のままにしてみます。 CreateUserWizard に適切なエラー メッセージが表示されます。 図 12 は、十分に強力でないパスワードを使用してユーザーを作成しようとしたときの出力を示しています。
図 12: CreateUserWizard で検証コントロールが自動的に挿入される (クリックするとフルサイズの画像が表示されます)
次に、CreateUserWizard に適切な値を入力し、[ユーザーの作成] ボタンをクリックします。 必須フィールドが入力されていて、パスワードの強度が十分であると仮定すると、CreateUserWizard では Membership フレームワークを使用して新しいユーザー アカウントが作成され、CompleteWizardStep
のインターフェイスが表示されます (図 13 を参照)。 CreateUserWizard では、手順 5 で行ったように、バックグラウンドで Membership.CreateUser
メソッドが呼び出されます。
図 13: 新しいユーザー アカウントが正常に作成された (クリックするとフルサイズの画像が表示されます)
Note
図 13 に示すように、CompleteWizardStep
のインターフェイスには [続行] ボタンが含まれています。 しかし、この時点でクリックするとポストバックが実行されるだけで、訪問者は同じページに残ります。 「CreateUserWizard の外観と動作をプロパティを使用してカスタマイズする」セクションでは、このボタンを使って訪問者を Default.aspx
(またはその他のページ) に送る方法を確認します。
新しいユーザー アカウントを作成した後、Visual Studio に戻り、図 10 で行ったように aspnet_Users
と aspnet_Membership
テーブルを調べて、アカウントが正常に作成されたことを確認します。
CreateUserWizard の動作と外観をプロパティを使用してカスタマイズする
CreateUserWizard は、プロパティ、WizardSteps
、イベント ハンドラーを使用して、さまざまな方法でカスタマイズできます。 このセクションでは、プロパティを使用してコントロールの外観をカスタマイズする方法を確認します。次のセクションでは、イベント ハンドラーを使用してコントロールの動作を拡張する方法を確認します。
CreateUserWizard コントロールの既定のユーザー インターフェイスに表示されるほとんどすべてのテキストは、多数のプロパティを使用してカスタマイズできます。 たとえば、テキスト ボックスの左側に表示される "ユーザー名"、"パスワード"、"パスワードの確認入力"、"メール"、"セキュリティの質問"、"セキュリティの回答" ラベルはそれぞれ、UserNameLabelText
、PasswordLabelText
、ConfirmPasswordLabelText
、EmailLabelText
、QuestionLabelText
、AnswerLabelText
プロパティでカスタマイズできます。 同様に、CreateUserWizardStep
と CompleteWizardStep
の [ユーザーの作成] と [続行] ボタンのテキストを指定するためのプロパティがあります。これらのボタンが Buttons、LinkButtons、または ImageButtons としてレンダリングされる場合も同様です。
色、罫線、フォント、およびその他のビジュアル要素は、スタイル プロパティのホストを通じて構成できます。 CreateUserWizard コントロール自体には、共通の Web コントロール スタイル プロパティ (BackColor
、BorderStyle
、CssClass
、Font
など) があり、CreateUserWizard のインターフェイスの特定のセクションの外観を定義するためのスタイル プロパティは多数あります。 たとえば、TextBoxStyle
プロパティでは CreateUserWizardStep
のテキスト ボックスのスタイルが定義されますが、TitleTextStyle
プロパティではタイトルのスタイル ("新しいアカウントにサインアップ") が定義されます。
外観関連のプロパティに加え、CreateUserWizard コントロールの動作に影響するプロパティは多数あります。 DisplayCancelButton
プロパティを True に設定すると、[ユーザーの作成] ボタンの横に [キャンセル] ボタンが表示されます (既定値は False です)。 [キャンセル] ボタンを表示する場合は、必ず、CancelDestinationPageUrl
プロパティも設定してください。これにより、[キャンセル] をクリックした後にユーザーが送られるページが指定されます。 前のセクションで説明したように、CompleteWizardStep
のインターフェイスの [続行] ボタンをクリックするとポストバックが発生しますが、訪問者は同じページに残ります。 [続行] ボタンをクリックした後、訪問者を他のページに送る場合は、ContinueDestinationPageUrl
プロパティで URL を指定するだけです。
RegisterUser
CreateUserWizard コントロールを更新して、[キャンセル] ボタンを表示し、[キャンセル] または [続行] ボタンがクリックされたときに訪問者を Default.aspx
に送ってみましょう。 これを実現するには、DisplayCancelButton
プロパティを True に設定し、CancelDestinationPageUrl
と ContinueDestinationPageUrl
プロパティの両方を "~/Default.aspx" に設定します。 図 14 は、ブラウザーで表示されたときの更新された CreateUserWizard を示しています。
図 14: CreateUserWizardStep
に [キャンセル] ボタンが含まれている (クリックするとフルサイズの画像が表示されます)
訪問者がユーザー名、パスワード、メール アドレス、セキュリティの質問と回答を入力し、[ユーザーの作成] をクリックすると、新しいユーザー アカウントが作成され、その新しく作成されたユーザーとして訪問者がログインします。 ページにアクセスするユーザーが自分で新しいアカウントを作成していると仮定すると、これは望ましい動作である可能性があります。 しかし、管理者に新しいユーザー アカウントの追加を許可する必要がある場合があります。 その場合、ユーザー アカウントは作成されますが、管理者は (新しく作成されたアカウントとしてではなく) 管理者としてログインしたままになります。 この動作は、ブール値の LoginCreatedUser
プロパティを使用して変更できます。
メンバーシップ フレームワークのユーザー アカウントには、承認済みフラグが含まれています。承認されていないユーザーは、サイトにログインできません。 既定では、新しく作成されたアカウントは承認済みとしてマークされ、ユーザーはすぐにサイトにログインできます。 しかし、新しいユーザー アカウントを未承認としてマークすることもできます。 新しいユーザーがログインする前に管理者が手動でそのユーザーを承認するようにしたい場合や、ユーザーにログオンを許可する前に、サインアップ時に入力されたメール アドレスが有効であることを確認したい場合があります。 いずれの場合も、CreateUserWizard コントロールの DisableCreatedUser
プロパティを True (既定値は False) に設定することで、新しく作成されたユーザー アカウントを未承認としてマークすることができます。
その他の動作に関連する注意事項のプロパティには、AutoGeneratePassword
と MailDefinition
が含まれます。 AutoGeneratePassword
プロパティが True に設定されている場合、CreateUserWizardStep
には [パスワード] と [パスワードの確認入力] テキスト ボックスは表示されません。代わりに、新しく作成されたユーザーのパスワードが、Membership
クラスの GeneratePassword
メソッドを使用して自動的に生成されます。 GeneratePassword
メソッドでは、指定された長さの、構成されたパスワード強度要件を満たすのに十分な数の英数字以外の文字を含むパスワードが構築されます。
MailDefinition
プロパティは、アカウントの作成プロセス中に指定されたメール アドレスにメールを送信する場合に便利です。 MailDefinition
プロパティには、構築されたメール メッセージに関する情報を定義するための一連のサブプロパティが含まれています。 これらのサブプロパティには、Subject
、Priority
、IsBodyHtml
、From
、CC
、BodyFileName
などのオプションが含まれています。 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
プロパティをクリアし、EnableViewState
と Visible
プロパティを 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 コントロールに入力されたユーザー名とパスワードは、それぞれ UserName
と Password
プロパティを介して使用できることに注意してください。 上記のイベント ハンドラーでこれらのプロパティを使用して、指定されたユーザー名の先頭または末尾にスペースが含まれているかどうか、およびユーザー名がパスワード内で見つかったかどうかを判断します。 これらの条件のいずれかが満たされると、エラー メッセージが InvalidUserNameOrPasswordMessage
Label に表示され、イベント ハンドラーの e.Cancel
プロパティが true
に設定されます。 e.Cancel
が true
に設定されている場合、CreateUserWizard ではワークフローが省略され、ユーザー アカウントの作成プロセスが実質的に取り消されます。
図 15 は、ユーザーが先頭にスペースを含むユーザー名を入力したときの CreatingUserAccounts.aspx
のスクリーンショットを示しています。
図 15: 先頭または末尾にスペースを含むユーザー名は許可されない (クリックするとフルサイズの画像が表示されます)
Note
CreateUserWizard コントロールの CreatedUser
イベントの使用例については、「追加のユーザー情報を格納する」チュートリアルで確認します。
まとめ
Membership
クラスの CreateUser
メソッドでは、メンバーシップ フレームワークに新しいユーザー アカウントが作成されます。 これは、構成されたメンバーシップ プロバイダーに呼び出しを委任することで行われます。 SqlMembershipProvider
の場合、CreateUser
メソッドでは、aspnet_Users
と aspnet_Membership
データベース テーブルにレコードが追加されます。
新しいユーザー アカウントはプログラムで作成できますが (手順 5 で確認したように)、CreateUserWizard コントロールを使用する方が高速で簡単です。 このコントロールでは、ユーザー情報を収集し、メンバーシップ フレームワークで新しいユーザーを作成するためのマルチステップ ユーザー インターフェイスがレンダリングされます。 このコントロールでは、内部的に、手順 5 で確認したのと同じ Membership.CreateUser
メソッドが使用されますが、ユーザー インターフェイス、検証コントロールが作成され、コードを 1 行も記述することなく、ユーザー アカウント作成エラーに応答します。
この時点で、新しいユーザー アカウントを作成する機能の準備ができました。 しかし、ログイン ページでは、2 番目のチュートリアルで指定したハードコーディングされた資格情報に対して引き続き検証が行われます。 次のチュートリアルでは、メンバーシップ フレームワークに対してユーザーが指定した資格情報を検証するために Login.aspx
を更新します。
プログラミングに満足!
もっと読む
この記事で説明したトピックの詳細については、次のリソースを参照してください。
CreateUser
テクニカル ドキュメント- CreateUserWizard コントロールの概要
- ファイル システム ベースのサイト マップ プロバイダーの作成
- ASP.NET 2.0 Wizard コントロールを使用したステップ バイ ステップ ユーザー インターフェイスの作成
- ASP.NET 2.0 のサイト ナビゲーションの確認
- マスター ページとサイト ナビゲーション
- 待ち望まれていた SQL サイト マップ プロバイダー
作成者について
複数の 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 までご一報ください。