SQL Server でメンバーシップ スキーマを作成する (C#)
Note
この記事の作成時以降に、ASP.NET メンバーシップ プロバイダーは ASP.NET Identity に置き換えられています。 この記事が作成された時点で紹介したメンバーシップ プロバイダーではなく、 ASP.NET Identity プラットフォームを使用するように、アプリを更新することを強く推奨します。 ASP.NET メンバーシップ システムと比較すると、ASP.NET Identity には次のような多くの利点があります。
- パフォーマンスの向上
- 向上した拡張性とテストの容易性
- OAuth、OpenID Connect、2 要素認証のサポート
- クレームベースの ID のサポート
- ASP.Net Core との相互運用性の向上
このチュートリアルでは、まず、SqlMembershipProvider を使用するために必要なスキーマをデータベースに追加する方法を調べることから始めます。 その後、スキーマのキー テーブルを調べ、その目的と重要性について説明していきます。 このチュートリアルは、メンバーシップ フレームワークが使用する必要があるプロバイダーを、ASP.NET アプリケーションに指示する方法について説明して終了します。
はじめに
前の 2 つのチュートリアルでは、フォーム認証を使用した Web サイトの訪問者の識別について見てきました。 フォーム認証フレームワークを使用すると、開発者はユーザーを Web サイトにログインさせ、認証チケットを使用して、そのユーザーをページ アクセス間で記憶することが簡単に行なえます。 この FormsAuthentication
クラスには、チケットを生成して、それを訪問者の Cookie に追加するためのメソッドが含まれています。 FormsAuthenticationModule
では、受信する要求がすべて調べられ、有効な認証チケットを持つ要求に対しては GenericPrincipal
と FormsIdentity
オブジェクトが作成され、それらが現在の要求に関連付けられます。 フォーム認証は、ログイン時に訪問者に認証チケットを付与し、それ以降の要求では、そのチケットを解析してユーザーの ID を判断するためだけのメカニズムです。 依然として、Web アプリケーションでユーザー アカウントをサポートするには、ユーザー ストアを実装し、資格情報の検証、新しいユーザーの登録、およびその他非常に多くのユーザー アカウント関連タスクを追加する必要があります。
ASP.NET 2.0 以前、開発者は、これらのユーザー アカウント関連のすべてのタスクを実装する仕事を背負っていました。 幸いなことに、ASP.NET チームはこの欠点を認識しており、ASP.NET 2.0 では、メンバーシップ フレームワークを導入しました。 メンバーシップ フレームワークは、NET Framework に含まれるクラスのセットであり、ユーザー アカウント関連の主要タスクを実行するためのプログラマティック インターフェイスを提供します。 このフレームワークはプロバイダー モデルの上に構築されており、開発者はカスタマイズされた実装を標準化された API にプラグインできます。
「セキュリティの基本と ASP.NET サポート」のチュートリアルで説明したように、.NET Framework には、2 つの組み込みのメンバーシップ プロバイダー、ActiveDirectoryMembershipProvider
および SqlMembershipProvider
が付属しています。 その名前が示すように、SqlMembershipProvider
では、ユーザー ストアとして Microsoft SQL Server データベースが使用されます。 アプリケーションでこのプロバイダーを使用するには、ストアとして使用するデータベースを、そのプロバイダーに伝える必要があります。 ご想像のとおり、SqlMembershipProvider
では、ユーザー ストア データベースに特定のデータベース テーブル、ビュー、ストアド プロシージャが備わっていることを想定しています。 この想定されたスキーマは、選択したデータベースに追加する必要があります。
このチュートリアルでは、まず、SqlMembershipProvider
を使用するために、必要なスキーマをデータベースに追加する手法を調べることから始めます。 その後、スキーマのキー テーブルを調べ、その目的と重要性について説明していきます。 このチュートリアルは、メンバーシップ フレームワークが使用する必要があるプロバイダーを、ASP.NET アプリケーションに指示する方法について説明して終了します。
それでは始めましょう。
手順 1: ユーザー ストアを配置する場所を決定する
ASP.NET アプリケーションのデータは、通常、データベース内の多数のテーブルに保存されます。 SqlMembershipProvider
データベース スキーマを実装する際には、メンバーシップ スキーマの配置場所を、アプリケーション データと同じデータベースにするか、代替データベースにするかを決定する必要があります。
メンバーシップ スキーマを置く場所は、次の理由から、アプリケーション データと同じデータベースにすることをお勧めします。
- 保守のしやすさ ' データが 1 つのデータベースにカプセル化されているアプリケーションは、2 つの別個のデータベースを持つアプリケーションよりも、理解、保守、およびデプロイが容易です。
- 関係の整合性 ' アプリケーション テーブルと同じデータベースにメンバーシップ関連のテーブルを配置することで、メンバーシップ関連テーブルと関連アプリケーション テーブルの主キーの間で、外部キーの制約を確立することができます。
ユーザー ストアとアプリケーション データを個別のデータベースに分離するのは、それぞれが個別のデータベースを使用する複数のアプリケーションを使用していて、それらが共通のユーザー ストアを共有する必要がある場合にのみ合理性があります。
データベースの作成
2 番目のチュートリアル以降に構築してきたアプリケーションは、これまでデータベースを必要としていませんでした。 しかしここでは、ユーザー ストアにそれが必要となります。 では、それを作成して、SqlMembershipProvider
プロバイダーに必要な スキーマを追加してみましょう (手順 2 を参照)。
Note
このチュートリアル シリーズでは、Microsoft SQL Server 2005 Express Edition データベースを使用 して、アプリケーション テーブルと SqlMembershipProvider
スキーマを保存していきます。 この決定には、次の 2 つの理由があります。第一に、コストが無料だということです。Express Edition は SQL Server 2005 でも最も読み取りとアクセスが簡単なバージョンです。第二に、SQL Server 2005 Express Edition データベースを、Web アプリケーションの App_Data
フォルダーに直接配置できることです。データベースと Web アプリケーションが 1 つの ZIP ファイルにパッケージ化できるので、特別なセットアップ手順や構成オプションなしで再デプロイできます。 Express Edition 以外のバージョンの SQL Server を使いたい場合も、難しく考える必要はありません。 手順は実質的に同じです。 SqlMembershipProvider
スキーマは、Microsoft SQL Server 2000 以上の任意のバージョンで動作します。
ソリューション エクスプローラーで、App_Data
フォルダーを右クリックし、[新しい項目の追加] を選択します。 (プロジェクトに App_Data
フォルダーが表示されない場合は、ソリューション エクスプローラーでプロジェクトを右クリックし、[ASP.NET フォルダーの追加]、App_Data
、の順に選択します)。[新しい項目の追加] ダイアログ ボックスで、SecurityTutorials.mdf
という名前の新しい SQL Database を選択します。 このチュートリアルでは、このデータベースに SqlMembershipProvider
スキーマを追加します。アプリケーション データをキャプチャするための追加のテーブルは、この後のチュートリアルで作成します。
図 1: App_Data
フォルダーに SecurityTutorials.mdf
という名前で新しい SQL Database データベースを追加する (クリックするとフルサイズの画像が表示されます)
App_Data
フォルダーに追加したデータベースは、自動的に、データベース エクスプローラー ビューにも表示されます。 (Express Edition バージョン以外の Visual Studio の場合、データベース エクスプローラーはサーバー エクスプローラーと呼ばれます。)データベース エクスプローラーに移動し、ここで追加した SecurityTutorials
データベースを展開します。 画面にデータベース エクスプローラーが表示されない場合は、[表示] メニューで [データベース エクスプローラー] を選択するか、Ctrl+Alt+S キーを押します。 図 2 に示すように、この SecurityTutorials
データベースは空の状態で、テーブルもビューもストアド プロシージャも含まれてでいません。
図 2: 現在、空の状態の SecurityTutorials
データベース (クリックするとフルサイズの画像が表示されます)
手順 2: データベースに SqlMembershipProvider
スキーマを追加する
SqlMembershipProvider
では、特定のテーブル、ビュー、ストアド プロシージャのセットを、ユーザー ストアのデータベースにインストールする必要があります。 これらの必要なデータベース オブジェクトは、aspnet_regsql.exe
ツールを使用して追加できます。 このファイルは %WINDIR%\Microsoft.Net\Framework\v2.0.50727\
フォルダー内で見つかります。
Note
aspnet_regsql.exe
ツールでは、コマンド ライン機能とグラフィカル ユーザー インターフェイスの両方が利用できます。 グラフィカルインターフェイスは、ユーザーにとって使いやすく、このチュートリアルではそれを確認していきます。 コマンド ライン インターフェイスは、ビルド スクリプトや自動テスト シナリオなどで、SqlMembershipProvider
スキーマの追加を自動化したい場合に便利です。
この aspnet_regsql.exe
ツールは、指定した SQL Server データベースにおいて、ASP.NET アプリケーション サービスを追加または削除するために使用されます。 ASP.NET アプリケーション サービスには、他の ASP.NET 2.0 フレームワーク向けの SQL ベース プロバイダーのスキーマと合わせて、SqlMembershipProvider
および SqlRoleProvider
向けのスキーマが含まれています。 aspnet_regsql.exe
ツールには、次の 2 ビットの情報を提供する必要があります。
- アプリケーション サービスを追加または削除するかどうか、および
- アプリケーション サービス スキーマの追加または削除元のデータベース
aspnet_regsql.exe
ツールは、使用するデータベースのプロンプトで、データベースが存在するサーバーの名前、データベースに接続するためのセキュリティ資格情報、および、そのデータベース名前を提供するよう要求します。 SQL Server の非 Express エディションを使用している場合も、ユーザーはこの情報を既に把握しています。これは、ASP.NET の Web ページからデータベースを操作するときに、接続文字列を経由して指定する必要があるものと同じ情報です。 ただし、App_Data
フォルダー内で SQL Server 2005 Express Edition データベースを使用する場合の、サーバー名とデータベース名の決定は、もう少し複雑になります。
次のセクションでは、App_Data
フォルダー内の SQL Server 2005 Express Edition データベースのサーバー名とデータベース名を、簡単に指定する方法について説明します。 SQL Server 2005 Express Edition を使用していない場合は、ここをスキップして、「Application Services のインストール」セクションに進むことができます。
App_Data
フォルダー内の SQL Server 2005 Express Edition データベースのサーバー名とデータベース名を決定する
この aspnet_regsql.exe
ツールを使用するには、サーバー名とデータベース名を知る必要があります。 サーバー名は localhost\InstanceName
です。 ほとんどの場合、InstanceName は SQLExpress
です。 ただし、SQL Server 2005 Express Edition を手動でインストールした場合 (つまり、Visual Studio のインストール中に自動的にインストールしなかった場合) には、異なるインスタンス名を選択している可能性があります。
データベース名の決定方法は少し複雑です。 通常、App_Data
フォルダー内のデータベースは、グローバルの一意識別子とデータベース ファイルへのパスを含む、データベース名を持っています。 aspnet_regsql.exe
を介しアプリケーション サービス スキーマを追加するには、このデータベースの名前を確定する必要があります。
データベース名を確認する最も簡単な方法は、SQL Server Management Studio を使用して調べることです。 SQL Server 2005 データベースを管理するためのグラフィカル インターフェイスは、SQL Server Management Studio では提供されますが、SQL Server 2005 の Express Edition には付属していません。 幸い、SQL Server Management Studio の無料の Express Edition をダウンロードすることができます。
Note
デスクトップに非 Express Edition バージョンの SQL Server 2005 もインストールされている場合なら、完全なバージョンの Management Studio がインストールされていると思います。 この完全なバージョンを使用して、以下で説明する手順に従っい、Express Edition 向けにデータベース名を決定できます。
まず、Visual Studio を閉じて、データベース ファイルに対して Visual Studio が課したすべてのロックが閉じられるようにします。 次に、SQL Server Management Studio を起動し、SQL Server 2005 Express Edition の localhost\InstanceName
データベースに接続します。 前述のように、インスタンス名は SQLExpress
なので助かります。 [認証] オプションで、[Windows 認証] を選択します。
図 3: SQL Server 2005 Express Edition インスタンスに接続する (クリックするとフルサイズの画像が表示されます)
SQL Server 2005 Express Edition インスタンスに接続すると、Management Studio にはデータベース、セキュリティ設定、サーバー オブジェクトなどのフォルダーが表示されます。 [データベース] タブを展開すると、SecurityTutorials.mdf
データベースがデータベース インスタンスに登録されて"いない"ことが表示 されます。つまり、データベースを最初にアタッチする必要があります。
[データベース] フォルダーを右クリックし、コンテキスト メニューから [アタッチ] を選択します。 これで、[データベースのアタッチ] ダイアログ ボックスが表示されます。 ここから [追加] ボタンをクリックし、SecurityTutorials.mdf
データベースを検索して、[OK] をクリックします。 図 4 は、SecurityTutorials.mdf
データベースが選択された後の、[データベースのアタッチ] ダイアログ ボックスを示しています。 図 5 は、データベースが正常にアタッチされた後の、Management Studio のオブジェクト エクスプローラーを示しています。
図 4: SecurityTutorials.mdf
データベースのアタッチ (クリックするとフルサイズの画像が表示されます)
図 5: データベース フォルダーに表示された SecurityTutorials.mdf
データベース (クリックするとフルサイズの画像が表示されます)
図 5 に示すように、SecurityTutorials.mdf
データベースの名前はかなり難解です。 これを、より記憶しやすい (入力しやすい) 名前に変更しましょう。 データベースを右クリックし、コンテキスト メニューから [名前の変更] を選択し、名前を「SecurityTutorialsDatabase
」に変更します。 これでも、ファイル名が変更されることはなく、SQL Server に対してデータベースが自身を特定するための名前が変更されるだけです。
図 6: データベースの名前を SecurityTutorialsDatabase
に変更する (クリックするとフルサイズの画像が表示されます)
この時点で、SecurityTutorials.mdf
データベース ファイル向けのサーバー名とデータベース名が、それぞれ、localhost\InstanceName
と SecurityTutorialsDatabase
であることがわかっています。 これで、aspnet_regsql.exe
ツールを使用してアプリケーション サービスをインストールする準備ができました。
Application Services のインストール
aspnet_regsql.exe
ツールを起動するには、スタート メニューに移動し、[実行] を選択します。 テキストボックスに「%WINDIR%\Microsoft.Net\Framework\v2.0.50727\aspnet_regsql.exe
」を入力し、[OK] をクリックします。 または、Windows のエクスプローラーを使用して、適切なフォルダーの内部に移動し、aspnet_regsql.exe
ファイルをダブルクリックすることもできます。 どちらの方法でも同じ結果が得られます。
コマンド ライン引数を一切指定せずに aspnet_regsql.exe
ツールを実行すると、ASP.NET SQL Server セットアップ ウィザードの、グラフィカル ユーザー インターフェイスが起動します。 ウィザードを使用すると、指定したデータベース上で、ASP.NET アプリケーション サービスを簡単に追加または削除できます。 図 7 に示したウィザードの最初の画面では、このツールの目的が説明されます。
図 7: ASP.NET SQL Server セットアップ ウィザードを使用してメンバーシップ スキーマを追加する (クリックするとフルサイズの画像が表示されます)
ウィザードの 2 番目の手順では、アプリケーション サービスを追加するか削除するかが質問されます。 ここでは、SqlMembershipProvider
に必要なテーブル、ビュー、ストアド プロシージャを追加しようとしているので、[アプリケーション サービス] のオプションで [SQL Server の構成] を選択します。 後でデータベースからこのスキーマを削除する場合、このウィザードを再実行しますが、その際は、[既存のデータベースからアプリケーション サービス情報を削除する] オプションを選択します。
図 8: アプリケーション サービスの [SQL Server の構成] オプションを選択する (クリックするとフルサイズの画像が表示されます)
3 番目の手順では、データベース情報 (サーバー名、認証情報、データベース名) の入力を求められます。 このチュートリアルに従ってきており、App_Data
に SecurityTutorials.mdf
データベースを追加 し、それを localhost\InstanceName
にアタッチし、さらに名前を SecurityTutorialsDatabase
に変更してあるのなら、次の値を使用します。
- サーバー:
localhost\InstanceName
- Windows 認証
- データベース:
SecurityTutorialsDatabase
図 9: データベース情報を入力する (クリックするとフルサイズの画像が表示されます)
データベース情報を入力したら、[次へ] をクリックします。 最後の手順では、実行される手順の概要が示されます。 [次へ] をクリックしてアプリケーション サービスをインストールし、[完了] をクリックしてこのウィザードを完了します。
Note
データベースのアタッチとデータベース ファイルの名前変更に Management Studio を使用した場合は、Visual Studio を再度開く前に、必ずデータベースをデタッチして Management Studio を閉じておきます。 SecurityTutorialsDatabase
データベースをデタッチするには、データベース名を右クリックし、[タスク] メニューから [デタッチ] を選択します。
ウィザードが完了したら、Visual Studio に戻り、データベース エクスプローラーに移動します。 [テーブル] フォルダーを展開します。 名前がプレフィックス aspnet_
で始まる一連のテーブルが表示されます。 同様に、さまざまなビューとストアド プロシージャが、ビュー フォルダーとストアド プロシージャ フォルダーの下で見つかります。 これらのデータベース オブジェクトが、アプリケーション サービス スキーマを構成しています。 メンバーシップおよびロールに固有のデータベース オブジェクトについては、手順 3 で見ていきます。
図 10: データベースに追加された各種のテーブル、ビュー、およびストアド プロシージャ (クリックするとフルサイズの画像が表示されます)
Note
aspnet_regsql.exe
ツールのグラフィカル ユーザー インターフェイスは、アプリケーション サービス スキーマ全体をインストールします。 また、コマンド ラインから aspnet_regsql.exe
を実行した場合には、インストール (または削除) したい特定のアプリケーション サービス コンポーネントを指定できます。 従って、SqlMembershipProvider
および SqlRoleProvider
プロバイダーに必要なテーブル、ビュー、およびストアド プロシージャのみを追加する場合は、コマンド ラインから aspnet_regsql.exe
を実行します。 その代わりに、aspnet_regsql.exe
で使用される T-SQL 作成スクリプトの適切なサブセットを、手動で実行することもできます。 これらのスクリプトは WINDIR%\Microsoft.Net\Framework\v2.0.50727\
フォルダーにあり、InstallCommon.sql
、InstallMembership.sql
、InstallRoles.sql
、InstallProfile.sql
、InstallSqlState.sql
などの名前が付けられています。
この時点で、SqlMembershipProvider
が必要とするデータベース オブジェクトが作成されています。 とはいえ、まだ、メンバーシップ フレームワークに対しては SqlMembershipProvider
を (ActiveDirectoryMembershipProvider
などではなく) 使用し、SqlMembershipProvider
に対しては SecurityTutorials
データベースを 使用するように、指示する必要があります。 手順 4 で、使用するプロバイダーを指定する方法と、選択したプロバイダーの設定をカスタマイズする方法について説明します。 しかし、まずは、先ほど作成したデータベース オブジェクトについて詳しく見ることにしましょう。
手順 3: スキーマのコア テーブルの概観
ASP.NET アプリケーションでメンバーシップ フレームワークとロール フレームワークを操作する場合、その実装の詳細はプロバイダーによってカプセル化されています。 この後のチュートリアルでは、.NET Framework の Membership
および Roles
クラスを介して、これらのフレームワークとインターフェイスしていきます。 これらの高度な API を使用すれば、どのクエリが実行されるかや、SqlMembershipProvider
および SqlRoleProvider
によってどのテーブルが変更されるかなどの、低レベルの詳細事項に気を払う必要はありません。
このため、手順 2 で作成したデータベース スキーマを調べることなく、メンバーシップとロールのフレームワークを安心して使用できます。 ただし、アプリケーション データを保存するためにテーブルを作成する場合は、ユーザーまたはロールに関連するエンティティの作成が必要になることがあります。 これは、手順 2 で作成した各 テーブルとアプリケーション データ テーブルとの間に外部キー制約を確立するとき、SqlMembershipProvider
と SqlRoleProvider
スキーマに関し情報を得るための役に立ちます。 さらに言うと、まれな状況においては、データベース レベルでユーザー ストアとロール ストアに (Membership
または Roles
クラス経由ではなく) 直接インターフェイスする必要性が生じることがあります。
アプリケーション内でのユーザー ストアのパーティション分割
メンバーシップとロールのフレームワークは、1 つのユーザーとロール ストアを、異なるアプリケーション間で共有できるように設計されています。 メンバーシップまたはロールのフレームワークを使用する ASP.NET アプリケーションでは、使用するアプリケーション パーティションを指定する必要があります。 つまり、複数の Web アプリケーションが、同じユーザー ストアとロール ストアを使用できます。 図 11 は、HRSite、CustomerSite、SalesSite の 3 つのアプリケーションにパーティション分割された、ユーザーストアとロール ストアを示しています。 これら 3 つの Web アプリケーションは、それぞれ独自かつ一意のユーザーとロールを持ちますが、すべてが同じデータベース テーブルにユーザー アカウントとロール情報を物理的に保存しています。
図 11: ユーザー アカウントは複数のアプリケーション間でパーティション分割できる (クリックするとフルサイズの画像が表示されます)
aspnet_Applications
テーブルが、これらのパーティションを定義しています。 データベースを使用してユーザー アカウント情報を保存する各アプリケーションが、このテーブルの行に表されています。 aspnet_Applications
テーブルには、ApplicationId
、ApplicationName
、LoweredApplicationName
、Description
の 4 つの列があります。 ApplicationId
の型は uniqueidentifier
であり、これがテーブルの主キーです。ApplicationName
は、アプリケーションごとに一意のわかりやすい名前を提供します。
メンバーシップとロールに関連する他のテーブルからは、aspnet_Applications
の ApplicationId
フィールドにリンクが返されています。 たとえば、各ユーザー アカウントのレコードを含む aspnet_Users
テーブルには、ApplicationId
の外部キー フィールドがあります (aspnet_Roles
についても同様)。 これらのテーブルの ApplicationId
フィールドは、ユーザー アカウントまたはロールが属するアプリケーション パーティションを指定します。
ユーザー アカウント情報の保存
ユーザー アカウント情報は、2 つのテーブル、aspnet_Users
および aspnet_Membership
に保存されます。 aspnet_Users
テーブルには、重要なユーザー アカウント情報を保持するフィールドが含まれています。 最も関連性のある列は次の 3 つです。
UserId
UserName
ApplicationId
UserId
は (型が uniqueidentifier
の) 主キーです。 UserName
は型が nvarchar(256)
で、パスワードと共にユーザーの資格情報を構成します。 (ユーザーのパスワードは aspnet_Membership
テーブルに保存されます。) ApplicationId
は、aspnet_Applications
内のアプリケーションにユーザー アカウントをリンクします。 UserName
と ApplicationId
列には複合的な UNIQUE
制約があります。 これにより、特定のアプリケーションの中の各 UserName は一意になりますが、異なるアプリケーションでは、同じ UserName
を使用できるようになります。
aspnet_Membership
テーブルには、ユーザーのパスワード、メールアドレス、最後のログイン日時など、追加的なユーザー アカウント情報が含まれています。 aspnet_Users
内のレコードと aspnet_Membership
テーブルの間は、1 対 1 で対応しています。 このリレーションシップは、aspnet_Membership
の UserId
フィールドによって保証され、これがテーブルの主キーとして機能します。 aspnet_Users
テーブルと同様に、aspnet_Membership
にも、この情報を特定のアプリケーション パーティションに紐付けるための、ApplicationId
フィールドが含まれています。
パスワードの保護
パスワードの情報は aspnet_Membership
テーブルに保存されます。 SqlMembershipProvider
を使用することで、3 つの手法のいずれかを使用して、データベースにパスワードを保存できます。
- クリア - パスワードはプレーンテキストとしてデータベースに保存されます。 このオプションは、使用しないことを強くお勧めします。 データベースが (バックドアを見つけたハッカーや、不満を持ちデータベースのアクセス権がある従業員などにより) 侵害された場合は、すべてのユーザーの資格情報が簡単に盗まれます。
- ハッシュ化 - パスワードは、一方向ハッシュ アルゴリズムとランダムに生成されたソルト値を使用して、ハッシュ化されます。 このハッシュ値は (ソルトと共に) データベースに保存されます。
- 暗号化 - 暗号化されたバージョンのパスワードがデータベースに保存されます。
使用されるパスワード ストレージの手法は、Web.config
で指定された SqlMembershipProvider
設定に応じて変わります。 SqlMembershipProvider
の設定をカスタマイズする方法については、手順 4 で見ていきます。 既定の動作では、パスワードのハッシュを保存します。
パスワードの保存先である列は Password
、PasswordFormat
、および PasswordSalt
です。 PasswordFormat
は、パスワードの保存に使用される手法を示す int
型の値を持つフィールドで、クリアの場合は 0、ハッシュ化の場合は 1、暗号化の場合は 2 です。 PasswordSalt
には、パスワードの保存に使用される手法に関係なく、ランダムに生成された文字列が割り当てられます。PasswordSalt
の値は、パスワードのハッシュを計算する場合にのみ使用されます。 最後に、Password
列には実際のパスワード データ (プレーンテキストのパスワード、パスワードのハッシュ、暗号化されたパスワード) が含まれます。
表 1 は、パスワード MySecret! を保存する際のさまざまなストレージ手法に対し、これら 3 つの列がどのようになるかを示しています 。
Storage Technique<_o3a_p /> | Password<_o3a_p /> | PasswordFormat<_o3a_p /> | PasswordSalt<_o3a_p /> |
---|---|---|---|
Clear | MySecret! | 0 | tTnkPlesqissc2y2SMEygA== |
ハッシュ | 2oXm6sZHWbTHFgjgkGQsc2Ec9ZM= | 1 | wFgjUfhdUFOCKQiI61vtiQ== |
Encrypted | 62RZgDvhxykkqsMchZ0Yly7HS6onhpaoCYaRxV8g0F4CW56OXUU3e7Inza9j9BKp | 2 | LSRzhGS/aa/oqAXGLHJNBw== |
表 1: パスワード MySecret! を保存する場合のパスワード関連フィールドの値の例
Note
SqlMembershipProvider
によって使用される、特定の暗号化アルゴリズムまたはハッシュ アルゴリズムは、<machineKey>
要素での設定によって決まります。
ロールとロールの関連付けの保存
ロール フレームワークを使用すると、開発者はロールのセットを定義し、どのユーザーがどのロールに属するかを指定できます。 この情報は、2 つのテーブル (aspnet_Roles
および aspnet_UsersInRoles
) を介してデータベースにキャプチャされます。 aspnet_Roles
テーブル内の各レコードは、特定のアプリケーションのロールを表します。 aspnet_Users
テーブルと同様に、この aspnet_Roles
テーブルは、ここでの説明に関連する 3 つの列を持っています。
RoleId
RoleName
ApplicationId
RoleId
は (型が uniqueidentifier
の) 主キーです。 RoleName
は nvarchar(256)
型です。 そして ApplicationId
は、ユーザー アカウントを aspnet_Applications
内の特定のアプリケーションにリンクします。 RoleName
および ApplicationId
列には複合的な UNIQUE
制約があり、特定のアプリケーションの中で各ロール名が一意になることを保証しています。
aspnet_UsersInRoles
テーブルは、ユーザーとロールの間でマッピングの機能を提供します。 存在する列は UserId
と RoleId
の 2 つのみで、これらがともに、複合的な主キーを構成します。
手順 4: プロバイダーを指定し、その設定をカスタマイズする
メンバーシップフレームワークやロール フレームワークなど、プロバイダー モデルをサポートするすべてのフレームワークには、実装の詳細が含まれていないので、代わりに責任をプロバイダー クラスに委任します。 メンバーシップ フレームワークの場合、Membership
クラスはユーザー アカウントを管理するための API を定義しますが、これがユーザー ストアと直接やり取りすることはありません。 むしろ、Membership
クラスのメソッドは、構成されたプロバイダーに要求を渡すので、ここでは SqlMembershipProvider
を使用しています。 Membership
クラス内のいずれかのメソッドを呼び出す場合、メンバーシップ フレームワークは、この呼び出しを SqlMembershipProvider
に委任することをどう認識するのでしょうか?
この Membership
クラスには、登録済みのすべてのプロバイダー クラスへの参照を含むProviders
プロパティがあり、メンバーシップ フレームワークが使用できます。 登録されたプロバイダーには、それぞれ名前と型が関連付けられています。 名前では、Providers
コレクション内の特定のプロバイダーを参照するためのわかりやすい方法が提供され、型ではプロバイダーのクラスが識別されます。 さらに、登録されている各プロバイダーには、構成設定を含めることもできます。 メンバーシップ フレームワークの構成設定には、多くの他の設定とともに、passwordFormat
と requiresUniqueEmail
が含まれています。 SqlMembershipProvider
で使用される構成設定の完全なリストについては、表 2 を参照してください。
Providers
プロパティの内容は、Web アプリケーションの構成設定を通じて指定されます。 既定では、すべての Web アプリケーションには、型が SqlMembershipProvider
で名前が AspNetSqlMembershipProvider
のプロバイダーがあります。 この既定のメンバーシップ プロバイダーは、machine.config
に登録されています (場所は %WINDIR%\Microsoft.Net\Framework\v2.0.50727\CONFIG)
)。
<membership>
<providers>
<add name="AspNetSqlMembershipProvider"
type="System.Web.Security.SqlMembershipProvider, System.Web, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"
connectionStringName="LocalSqlServer"
enablePasswordRetrieval="false"
enablePasswordReset="true"
requiresQuestionAndAnswer="true"
applicationName="/"
requiresUniqueEmail="false"
passwordFormat="Hashed"
maxInvalidPasswordAttempts="5"
minRequiredPasswordLength="7"
minRequiredNonalphanumericCharacters="1"
passwordAttemptWindow="10"
passwordStrengthRegularExpression=""/>
</providers>
</membership>
上のマークアップが示すように、<membership>
要素はメンバーシップ フレームワークの構成設定を定義する一方、子要素 <providers>
は登録済みのプロバイダーを指定します。 プロバイダーは、<add>
または <remove>
要素を使用して追加または削除できます。現在登録されているすべてのプロバイダーを削除するには、<clear>
要素を使用します。 上のマークアップに示すように、machine.config
は、型が SqlMembershipProvider
で名前が AspNetSqlMembershipProvider
のプロバイダーを追加します。
name
および type
属性に加えて、<add>
要素には、さまざまな構成設定に対し値を定義する属性が含まれています。 表 2 に、SqlMembershipProvider
に固有で使用可能な構成設定と、それぞれの説明を示します。
Note
表 2 に示されている既定値は、SqlMembershipProvider
クラスで定義されている既定値を参照します。 AspNetSqlMembershipProvider
の中のすべての構成設定が、SqlMembershipProvider
クラスの既定値に対応しているわけではないことに注意してください。 たとえば、メンバーシップ プロバイダーで指定されていなければ、requiresUniqueEmail
設定の既定値は true になります。 ただし、false
値を明示的に指定することで、AspNetSqlMembershipProvider
がこの既定値をオーバーライドします。
Setting<_o3a_p /> | Description<_o3a_p /> |
---|---|
ApplicationName |
メンバーシップ フレームワークを使用すると、1 つのユーザー ストアを複数のアプリケーション間でパーティション分割できることを思い出してください。 この設定は、メンバーシップ プロバイダーが使用するアプリケーション パーティションの名前を示します。 この値が明示的に指定されていない場合は、実行時に、アプリケーションの仮想ルート パスの値に設定されます。 |
commandTimeout |
SQL コマンドのタイムアウト値 (秒単位) を指定します。 既定値は 30 です。 |
connectionStringName |
ユーザー ストア データベースへの接続に使用する、<connectionStrings> 要素内の接続文字列の名前。 この値は必須です。 |
description |
登録済みプロバイダーの、わかりやすい説明を提供します。 |
enablePasswordRetrieval |
ユーザーが忘れたパスワードを取得できるかどうかを指定します。 既定値は false です。 |
enablePasswordReset |
ユーザーが自分のパスワードをリセットできるかどうかを示します。 既定値は true です。 |
maxInvalidPasswordAttempts |
ユーザーがロックアウトされる前に、指定された passwordAttemptWindow の中でユーザーが試行できるログインの失敗の最大回数。既定値は 5 です。 |
minRequiredNonalphanumericCharacters |
ユーザーのパスワードに含める必要がある、英数字以外の文字の最小数。 この値は 0 から 128 の間である必要があります。既定値は 1 です。 |
minRequiredPasswordLength |
パスワードに必要な最小文字数。 この値は 0 から 128 の間である必要があります。既定値は 7 です。 |
name |
登録済みプロバイダーの名前。 この値は必須です。 |
passwordAttemptWindow |
失敗したログインの試行が追跡される分数。 ユーザーが、この指定されたウィンドウ内に無効なログイン資格情報を maxInvalidPasswordAttempts 回指定した場合、そのユーザーはロックアウトされます。既定値は 10 です。 |
PasswordFormat |
パスワード ストレージの形式: Clear 、Hashed 、または Encrypted 。 既定値は、Hashed です。 |
passwordStrengthRegularExpression |
指定した場合、この正規表現は、新しいアカウントの作成かパスワードの変更時に、ユーザーが選択したパスワードの強度を評価するために使用されます。 既定値は空の文字列です。 |
requiresQuestionAndAnswer |
ユーザーが自分のパスワードを取得またはリセットする場合、セキュリティの質問に回答する必要があるかどうかを指定します。 既定値は true です。 |
requiresUniqueEmail |
特定のアプリケーション パーティション内のすべてのユーザー アカウントに、一意のメール アドレスが要求されるかどうかを示します。 既定値は true です。 |
type |
プロバイダーの種類を指定します。 この値は必須です。 |
表 2: メンバーシップと SqlMembershipProvider
の構成設定
AspNetSqlMembershipProvider
に加えて、同様のマークアップを Web.config
ファイルに追加することで、アプリケーションごとに他のメンバーシップ プロバイダーを登録できます。
Note
ロール フレームワークの機能もほぼ同様で、machine.config
には既定の登録済みロール プロバイダーがあり、登録されたプロバイダーは、Web.config
の中でアプリケーションごとにカスタマイズできます。 今後のチュートリアルでは、ロール フレームワークとその構成マークアップについて詳しく説明します。
SqlMembershipProvider
の設定のカスタマイズ
既定の SqlMembershipProvider
(AspNetSqlMembershipProvider
) の connectionStringName
属性は、LocalSqlServer
に設定されています。 AspNetSqlMembershipProvider
プロバイダーと同様に、接続文字列名 LocalSqlServer
は、machine.config
で定義されます。.
<connectionStrings>
<add name="LocalSqlServer"
connectionString="data source=.\SQLEXPRESS;Integrated Security=SSPI;AttachDBFilename=|DataDirectory|aspnetdb.mdf;User Instance=true"
providerName="System.Data.SqlClient"/>
</connectionStrings>
ご覧のとおり、この接続文字列では、|DataDirectory|aspnetdb.mdf' にある SQL 2005 Express Edition データベースが定義されています。 文字列 |DataDirectory| は、~/App_Data/
ディレクトリを指すために実行時に変換されるため、データベース パス |DataDirectory|aspnetdb.mdf" は ~/App_Data
/aspnet.mdf
に変換されます。
アプリケーションの Web.config
ファイルにメンバーシップ プロバイダー情報を指定していないなら、アプリケーションは既定の登録済みメンバーシップ プロバイダー (AspNetSqlMembershipProvider
) を使用します。 ~/App_Data/aspnet.mdf
データベースが存在しない場合には、ASP.NET ランタイムで自動的に作成され、さらにアプリケーション サービス スキーマが追加されます。 ただし、ここでは aspnet.mdf
データベースは使用しません。代わりに、手順 2 で作成した SecurityTutorials.mdf
データベースを使用します。 この変更は、次の 2 つの方法のいずれかで達成されます。
Web.config
で、LocalSqlServer
接続文字列名の値を指定します。Web.config
で接続文字列名の値LocalSqlServer
を上書きすることで、既定の登録済みメンバーシップ プロバイダー (AspNetSqlMembershipProvider
) を使用し、これをSecurityTutorials.mdf
データベースと正しく連携させることができます。AspNetSqlMembershipProvider
で指定されている構成設定に満足しているのなら、この方法で問題ありません。 この手法の詳細については、Scott Guthrie 氏のブログ投稿、「ASP.NET 2.0 Application Services を構成して SQL Server 2000 または SQL Server 2005 を使用する」を参照してください。SqlMembershipProvider
型の新しい登録済みプロバイダーを追加し、SecurityTutorials.mdf
データベースを指すようにconnectionStringName
設定を構成します。このアプローチは、データベース接続文字列に加えて、他の構成プロパティをカスタマイズする場合に便利です。 私自身のプロジェクトでは、柔軟性と読みやすさのために、常にこのアプローチを使用しています。
SecurityTutorials.mdf
データベースを参照する新しい登録済みプロバイダーを追加する前に、Web.config
の <connectionStrings>
セクションに適切な接続文字列値を追加する必要があります。 次のマークアップは、App_Data
フォルダー内にある SQL Server 2005 Express Edition の SecurityTutorials.mdf
データベースを参照する、SecurityTutorialsConnectionString
という名前の新しい接続文字列を追加します。
<configuration>
<connectionStrings>
<add name="SecurityTutorialsConnectionString"
connectionString="Data Source=.\SQLEXPRESS;AttachDbFilename=|DataDirectory|\SecurityTutorials.mdf;Integrated Security=True;User Instance=True"
providerName="System.Data.SqlClient"/>
</connectionStrings>
<system.web>
... Configuration markup removed for brevity ...
</system.web>
</configuration>
Note
代替のデータベース ファイルを使用している場合は、必要に応じて接続文字列を更新します。 適切な接続文字列の形成の詳細については、ConnectionStrings.com を参照してください。
次に、下記のメンバーシップ構成マークアップを Web.config
ファイルに追加します。 このマークアップでは、SecurityTutorialsSqlMembershipProvider
という名前の新しいプロバイダーが登録されます。
<configuration>
<connectionStrings>
<add name="SecurityTutorialsConnectionString"
connectionString="Data Source=.\SQLEXPRESS;AttachDbFilename=|DataDirectory|\SecurityTutorials.mdf;Integrated Security=True;User Instance=True"
providerName="System.Data.SqlClient"/>
</connectionStrings>
<system.web>
<membership defaultProvider="SecurityTutorialsSqlMembershipProvider">
<providers>
<!--Add a customized SqlMembershipProvider -->
<add name="SecurityTutorialsSqlMembershipProvider"
type="System.Web.Security.SqlMembershipProvider"
connectionStringName="SecurityTutorialsConnectionString"
enablePasswordRetrieval="false"
enablePasswordReset="true"
requiresQuestionAndAnswer="true"
applicationName="SecurityTutorials"
requiresUniqueEmail="true"
passwordFormat="Hashed"
maxInvalidPasswordAttempts="5"
minRequiredPasswordLength="7"
minRequiredNonalphanumericCharacters="1"
passwordAttemptWindow="10"
passwordStrengthRegularExpression=""/>
</providers>
</membership>
... Configuration markup removed for brevity ...
</system.web>
</configuration>
SecurityTutorialsSqlMembershipProvider
プロバイダーの登録に加えて、上記のマークアップでは、既定のプロバイダーとして (<membership>
要素内の defaultProvider
属性を介し) SecurityTutorialsSqlMembershipProvider
を定義します。 メンバーシップ フレームワークには、複数の登録済みプロバイダーを含めることができることを思い出してください。 AspNetSqlMembershipProvider
は、machine.config
で最初のプロバイダーとして登録されているため、特に指定しない限り、これが既定のプロバイダーとして機能します。
現在、このアプリケーションには、2 つの登録済みプロバイダー (AspNetSqlMembershipProvider
および SecurityTutorialsSqlMembershipProvider
) が含まれています。 ただし、SecurityTutorialsSqlMembershipProvider
プロバイダーを登録する前に、<add>
要素の直前に <clear />
要素を追加することで、以前に登録されたすべてのプロバイダーをクリアしておくこともできます。 これにより、登録済みプロバイダーのリストから AspNetSqlMembershipProvider
が消去されます。つまり、SecurityTutorialsSqlMembershipProvider
が唯一の登録されているメンバーシップ プロバイダーになります。 この方法を使用した場合は、SecurityTutorialsSqlMembershipProvider
を既定のプロバイダーとしてマークする必要はありません。これが、唯一の登録されているメンバーシップ プロバイダーとなるためです。 <clear />
の使用の詳細情報については、「プロバイダー追加時の <clear />
の使用」を参照してください。
SecurityTutorialsSqlMembershipProvider
の connectionStringName
設定は、ここで追加された SecurityTutorialsConnectionString
接続文字列の名前を参照し、その applicationName
設定の値が SecurityTutorials に設定されていることに注意してください。 さらに、requiresUniqueEmail
設定は true
に設定されています。 その他のすべての構成オプションは、AspNetSqlMembershipProvider
の値と同じです。 必要に応じて、ここでの構成は自由に変更してください。 たとえば、英数字以外の文字を 1 つではなく 2 つ要求する、あるいはパスワードの長さを 7 文字ではなく 8 文字に増やすことで、パスワードの強度を強化できます。
Note
メンバーシップ フレームワークを使用すると、1 つのユーザー ストアを複数のアプリケーション間でパーティション分割できることを思い出してください。 メンバーシップ プロバイダーの applicationName
設定は、ユーザー ストアと連携する場合に、どのアプリケーションをプロバイダーが使用するのかを示します。 applicationName
構成設定の値を、明示的に設定することは重要です。applicationName
が明示的に設定されていない場合、実行時にこれが Web アプリケーションの仮想ルート パスに割り当てられるためです。 これは、アプリケーションの仮想ルート パスが変更されない限り正常に動作しますが、アプリケーションを別のパスに移動した場合には、applicationName
設定も変更されます。 これが起きると、メンバーシップ プロバイダーは、以前に使用したアプリケーション パーティションとは異なるアプリケーション パーティションを操作するようになります。 移動前に作成されたユーザー アカウントは別のアプリケーション パーティションに存在することとなり、それらのユーザーはサイトにログインできなくなります。 この問題のより詳細な議論については、「ASP.NET 2.0 メンバーシップとその他のプロバイダーを構成するときに常に applicationName
プロパティを設定する」を参照してください。
まとめ
この時点で、アプリケーション サービス (SecurityTutorials.mdf
) が構成されたデータベースがあり、Web アプリケーションの構成を終えています。つまり、メンバーシップ フレームワークは、ここで登録した SecurityTutorialsSqlMembershipProvider
プロバイダーを使用するようになっています。 この登録済みプロバイダーの型は SqlMembershipProvider
で、connectionStringName
は適切な接続文字列 (SecurityTutorialsConnectionString
) に設定されており、applicationName
値が明示的に設定されています。
この段階で、アプリケーションからメンバーシップ フレームワークを使用する準備ができています。 次のチュートリアルでは、新しいユーザー アカウントを作成する方法について説明します。 その後で、ユーザーの認証、ユーザー ベースの認可の実行、および追加のユーザー関連情報のデータベースへの保存について見ていきます。
プログラミングに満足!
もっと読む
この記事で説明したトピックの詳細については、次のリソースを参照してください。
- ASP.NET 2.0 メンバーシップとその他のプロバイダーを構成するときに常に
applicationName
プロパティを設定する - ASP.NET 2.0 Application Services を構成して SQL Server 2000 または SQL Server 2005 を使用する
- SQL Server Management Studio をダウンロード
- ASP.NET 2.0 のメンバーシップ、ロール、プロファイルを確認する
- メンバーシップのプロバイダー向けの
<add>
要素 <membership>
要素- Membership の
<providers>
要素 - プロバイダーの追加時の
<clear />
の使用 SqlMembershipProvider
を直接操作する
このチュートリアルに含まれるトピックに関するビデオ トレーニング
作成者について
複数の ASP/ASP.NET 書籍の著者であり、4GuysFromRolla.com の創設者である Scott Mitchell 氏は、1998 年から Microsoft Web のテクノロジに取り組んでいます。 Scott は、独立したコンサルタント、トレーナー、ライターとして働いています。 彼の最新の本は サムズは24時間で2.0 ASP.NET 自分自身を教えています。 Mitchell 氏には、mitchell@4guysfromrolla.com から、または http://ScottOnWriting.NET で彼のブログを介して連絡できます。
特別な感謝
このチュートリアル シリーズは、多くの役に立つ校閲者によってレビューされました。 このチュートリアルのリード レビュー担当者は、Alicja Maziarz でした。 今後の MSDN の記事を確認することに関心がありますか? ご希望なら、mitchell@4GuysFromRolla.com でメッセージをお送りください。.