のカスタムストレージプロバイダー ASP.NET Core IdentityCustom storage providers for ASP.NET Core Identity

作成者: Steve SmithBy Steve Smith

ASP.NET Core Identity は拡張可能なシステムであり、カスタム記憶域プロバイダーを作成してアプリに接続することができます。ASP.NET Core Identity is an extensible system which enables you to create a custom storage provider and connect it to your app. このトピックでは、用にカスタマイズされた記憶域プロバイダーを作成する方法について説明し ASP.NET Core Identity ます。This topic describes how to create a customized storage provider for ASP.NET Core Identity. この記事では、独自の記憶域プロバイダーを作成するための重要な概念について説明しますが、詳細な手順については説明しません。It covers the important concepts for creating your own storage provider, but isn't a step-by-step walkthrough.

GitHub のサンプルを表示またはダウンロードしてくださいView or download sample from GitHub.

はじめにIntroduction

既定では、 ASP.NET Core Identity システムは Entity Framework Core を使用して、ユーザー情報を SQL Server データベースに格納します。By default, the ASP.NET Core Identity system stores user information in a SQL Server database using Entity Framework Core. 多くのアプリでは、この方法が適しています。For many apps, this approach works well. ただし、別の永続化メカニズムまたはデータスキーマを使用することをお勧めします。However, you may prefer to use a different persistence mechanism or data schema. 次に例を示します。For example:

  • Azure Table Storageまたは別のデータストアを使用します。You use Azure Table Storage or another data store.
  • データベーステーブルの構造が異なります。Your database tables have a different structure.
  • Dapperなど、別のデータアクセス方法を使用することもできます。You may wish to use a different data access approach, such as Dapper.

これらの各ケースでは、ストレージメカニズム用にカスタマイズされたプロバイダーを作成し、そのプロバイダーをアプリに接続できます。In each of these cases, you can write a customized provider for your storage mechanism and plug that provider into your app.

ASP.NET Core Identity は、Visual Studio の [個別のユーザーアカウント] オプションを使用してプロジェクトテンプレートに含まれています。ASP.NET Core Identity is included in project templates in Visual Studio with the "Individual User Accounts" option.

.NET Core CLI を使用する場合は、次のように追加し -au Individual ます。When using the .NET Core CLI, add -au Individual:

dotnet new mvc -au Individual

ASP.NET Core IdentityアーキテクチャThe ASP.NET Core Identity architecture

ASP.NET Core Identity は、マネージャーおよびストアと呼ばれるクラスで構成されます。ASP.NET Core Identity consists of classes called managers and stores. マネージャー は、アプリ開発者がユーザーの作成などの操作を実行するために使用する高レベルのクラスです Identity 。Managers are high-level classes which an app developer uses to perform operations, such as creating an Identity user. ストア は、ユーザーやロールなどのエンティティがどのように永続化されるかを指定する下位レベルのクラスです。Stores are lower-level classes that specify how entities, such as users and roles, are persisted. ストアはリポジトリパターンに従い、永続化メカニズムと密接に結び付いています。Stores follow the repository pattern and are closely coupled with the persistence mechanism. マネージャーはストアから切り離されています。つまり、アプリケーションコードを変更することなく永続化メカニズムを置き換えることができます (構成を除く)。Managers are decoupled from stores, which means you can replace the persistence mechanism without changing your application code (except for configuration).

次の図は、web アプリがマネージャーと対話する方法を示しています。また、ストアはデータアクセス層と対話します。The following diagram shows how a web app interacts with the managers, while stores interact with the data access layer.

ASP.NET Core アプリは、マネージャー (たとえば、' UserManager ', ' RoleManager ') と連携します。

カスタム記憶域プロバイダーを作成するには、データソース、データアクセス層、およびこのデータアクセス層と対話するストアクラスを作成します (上の図の緑と灰色のボックス)。To create a custom storage provider, create the data source, the data access layer, and the store classes that interact with this data access layer (the green and grey boxes in the diagram above). マネージャーや、それらと対話するアプリコード (上の青いボックス) をカスタマイズする必要はありません。You don't need to customize the managers or your app code that interacts with them (the blue boxes above).

の新しいインスタンスを作成する場合、 UserManager または RoleManager ユーザークラスの型を指定し、ストアクラスのインスタンスを引数として渡します。When creating a new instance of UserManager or RoleManager you provide the type of the user class and pass an instance of the store class as an argument. この方法を使用すると、カスタマイズしたクラスを ASP.NET Core に組み込むことができます。This approach enables you to plug your customized classes into ASP.NET Core.

新しいストレージプロバイダーを使用するようにアプリを再構成 する UserManager カスタムストアでとをインスタンス化する方法について説明し RoleManager ます。Reconfigure app to use new storage provider shows how to instantiate UserManager and RoleManager with a customized store.

ASP.NET Core Identity データ型を格納しますASP.NET Core Identity stores data types

ASP.NET Core Identity データ型の詳細については、次のセクションを参考にしてください。ASP.NET Core Identity data types are detailed in the following sections:

ユーザーUsers

Web サイトの登録済みユーザー。Registered users of your web site. Identity ユーザーの種類は、独自のカスタム型の例として拡張または使用できます。The IdentityUser type may be extended or used as an example for your own custom type. 独自のカスタム id ストレージソリューションを実装するために、特定の型から継承する必要はありません。You don't need to inherit from a particular type to implement your own custom identity storage solution.

ユーザー要求User Claims

ユーザーの id を表す、ユーザーに関する一連のステートメント (または 要求)。A set of statements (or Claims) about the user that represent the user's identity. では、ロールを使用した場合よりも多くのユーザー id を有効にすることができます。Can enable greater expression of the user's identity than can be achieved through roles.

ユーザーログインUser Logins

ユーザーのログイン時に使用する外部認証プロバイダー (Facebook や Microsoft アカウントなど) に関する情報。Information about the external authentication provider (like Facebook or a Microsoft account) to use when logging in a user. Example

ロールRoles

サイトの承認グループ。Authorization groups for your site. ロール Id とロール名 ("Admin" や "Employee" など) が含まれます。Includes the role Id and role name (like "Admin" or "Employee"). Example

データアクセス層The data access layer

このトピックでは、使用する永続化メカニズムについて理解していること、およびそのメカニズムのエンティティを作成する方法について理解していることを前提としています。This topic assumes you are familiar with the persistence mechanism that you are going to use and how to create entities for that mechanism. このトピックでは、リポジトリまたはデータアクセスクラスの作成方法の詳細については説明しません。を使用する場合の設計上の決定について、いくつかの提案を提供 ASP.NET Core Identity します。This topic doesn't provide details about how to create the repositories or data access classes; it provides some suggestions about design decisions when working with ASP.NET Core Identity.

カスタマイズされたストアプロバイダーのデータアクセス層を設計する際には、自由度が高くなります。You have a lot of freedom when designing the data access layer for a customized store provider. アプリで使用する予定の機能に対してのみ、永続化メカニズムを作成する必要があります。You only need to create persistence mechanisms for features that you intend to use in your app. たとえば、アプリでロールを使用していない場合は、ロールまたはユーザーロールの関連付け用のストレージを作成する必要はありません。For example, if you are not using roles in your app, you don't need to create storage for roles or user role associations. テクノロジと既存のインフラストラクチャでは、の既定の実装とは大きく異なる構造が必要になる場合があり ASP.NET Core Identity ます。Your technology and existing infrastructure may require a structure that's very different from the default implementation of ASP.NET Core Identity. データアクセス層では、ストレージ実装の構造を操作するロジックを提供します。In your data access layer, you provide the logic to work with the structure of your storage implementation.

データアクセス層は、からデータソースにデータを保存するためのロジックを提供し ASP.NET Core Identity ます。The data access layer provides the logic to save the data from ASP.NET Core Identity to a data source. カスタマイズした記憶域プロバイダーのデータアクセス層には、ユーザーとロールの情報を格納するための次のクラスが含まれている場合があります。The data access layer for your customized storage provider might include the following classes to store user and role information.

Context クラスContext class

永続化メカニズムに接続してクエリを実行するための情報をカプセル化します。Encapsulates the information to connect to your persistence mechanism and execute queries. いくつかのデータクラスには、通常、依存関係の挿入によって提供されるこのクラスのインスタンスが必要です。Several data classes require an instance of this class, typically provided through dependency injection. Example.

ユーザーストレージUser Storage

ユーザー情報 (ユーザー名やパスワードハッシュなど) を格納および取得します。Stores and retrieves user information (such as user name and password hash). Example

ロールストレージRole Storage

ロール名などのロール情報を格納および取得します。Stores and retrieves role information (such as the role name). Example

UserClaims ストレージUserClaims Storage

ユーザー要求情報 (要求の種類や値など) を格納および取得します。Stores and retrieves user claim information (such as the claim type and value). Example

UserLogins ストレージUserLogins Storage

ユーザーのログイン情報 (外部認証プロバイダーなど) を格納および取得します。Stores and retrieves user login information (such as an external authentication provider). Example

UserRole ストレージUserRole Storage

どのロールがどのユーザーに割り当てられているかを格納および取得します。Stores and retrieves which roles are assigned to which users. Example

ヒント: アプリで使用する予定のクラスのみを実装します。TIP: Only implement the classes you intend to use in your app.

データアクセスクラスで、永続化メカニズムのデータ操作を実行するコードを指定します。In the data access classes, provide code to perform data operations for your persistence mechanism. たとえば、カスタムプロバイダー内で、 ストア クラスに新しいユーザーを作成するには、次のコードが必要になることがあります。For example, within a custom provider, you might have the following code to create a new user in the store class:

public async Task<IdentityResult> CreateAsync(ApplicationUser user, 
    CancellationToken cancellationToken = default(CancellationToken))
{
    cancellationToken.ThrowIfCancellationRequested();
    if (user == null) throw new ArgumentNullException(nameof(user));

    return await _usersTable.CreateAsync(user);
}

ユーザーを作成するための実装ロジックは、次に示すメソッドに含まれてい _usersTable.CreateAsync ます。The implementation logic for creating the user is in the _usersTable.CreateAsync method, shown below.

ユーザークラスをカスタマイズするCustomize the user class

ストレージプロバイダーを実装する場合は、 Identity user クラスと同等のユーザークラスを作成します。When implementing a storage provider, create a user class which is equivalent to the IdentityUser class.

少なくとも、ユーザークラスにはプロパティとプロパティが含まれている必要があり Id UserName ます。At a minimum, your user class must include an Id and a UserName property.

IdentityUserクラスは、要求された操作の実行時にが呼び出すプロパティを定義し UserManager ます。The IdentityUser class defines the properties that the UserManager calls when performing requested operations. プロパティの既定の型 Id は文字列ですが、から継承して別の型を指定することもでき IdentityUser<TKey, TUserClaim, TUserRole, TUserLogin, TUserToken> ます。The default type of the Id property is a string, but you can inherit from IdentityUser<TKey, TUserClaim, TUserRole, TUserLogin, TUserToken> and specify a different type. フレームワークでは、ストレージの実装がデータ型の変換を処理することを想定しています。The framework expects the storage implementation to handle data type conversions.

ユーザーストアをカスタマイズするCustomize the user store

ユーザーの UserStore すべてのデータ操作のメソッドを提供するクラスを作成します。Create a UserStore class that provides the methods for all data operations on the user. このクラスは、 Userstore < tuser > クラスに相当します。This class is equivalent to the UserStore<TUser> class. クラスで UserStoreIUserStore<TUser> および必要に応じて省略可能なインターフェイスを実装します。In your UserStore class, implement IUserStore<TUser> and the optional interfaces required. 実装するオプションのインターフェイスは、アプリで提供される機能に基づいて選択します。You select which optional interfaces to implement based on the functionality provided in your app.

省略可能なインターフェイスOptional interfaces

オプションのインターフェイスは、から継承され IUserStore<TUser> ます。The optional interfaces inherit from IUserStore<TUser>. サンプルアプリには、部分的に実装されたサンプルユーザーストアが表示されます。You can see a partially implemented sample user store in the sample app.

クラス内では、 UserStore 操作を実行するために作成したデータアクセスクラスを使用します。Within the UserStore class, you use the data access classes that you created to perform operations. これらは、依存関係の挿入を使用して渡されます。These are passed in using dependency injection. たとえば、Dapper 実装の SQL Server では、クラスに UserStore は、 CreateAsync のインスタンスを使用して DapperUsersTable 新しいレコードを挿入するメソッドがあります。For example, in the SQL Server with Dapper implementation, the UserStore class has the CreateAsync method which uses an instance of DapperUsersTable to insert a new record:

public async Task<IdentityResult> CreateAsync(ApplicationUser user)
{
    string sql = "INSERT INTO dbo.CustomUser " +
        "VALUES (@id, @Email, @EmailConfirmed, @PasswordHash, @UserName)";

    int rows = await _connection.ExecuteAsync(sql, new { user.Id, user.Email, user.EmailConfirmed, user.PasswordHash, user.UserName });

    if(rows > 0)
    {
        return IdentityResult.Success;
    }
    return IdentityResult.Failed(new IdentityError { Description = $"Could not insert user {user.Email}." });
}

ユーザーストアをカスタマイズするときに実装するインターフェイスInterfaces to implement when customizing user store

  • IUserStoreIUserStore
    IUserStore < tuser > インターフェイスは、ユーザーストアに実装する必要がある唯一のインターフェイスです。The IUserStore<TUser> interface is the only interface you must implement in the user store. ユーザーの作成、更新、削除、および取得を行うためのメソッドを定義します。It defines methods for creating, updating, deleting, and retrieving users.
  • IUserClaimStoreIUserClaimStore
    IUserClaimStore < tuser > インターフェイスでは、ユーザーの信頼性情報を有効にするために実装するメソッドを定義します。The IUserClaimStore<TUser> interface defines the methods you implement to enable user claims. これには、ユーザー要求を追加、削除、および取得するためのメソッドが含まれています。It contains methods for adding, removing and retrieving user claims.
  • IUserLoginStoreIUserLoginStore
    IUserLoginStore < tuser > は、外部認証プロバイダーを有効にするために実装するメソッドを定義します。The IUserLoginStore<TUser> defines the methods you implement to enable external authentication providers. これには、ユーザーログインを追加、削除、取得するためのメソッド、およびログイン情報に基づいてユーザーを取得するためのメソッドが含まれています。It contains methods for adding, removing and retrieving user logins, and a method for retrieving a user based on the login information.
  • IUserRoleStoreIUserRoleStore
    IUserRoleStore < tuser > インターフェイスでは、ユーザーをロールにマップするために実装するメソッドを定義します。The IUserRoleStore<TUser> interface defines the methods you implement to map a user to a role. これには、ユーザーのロールを追加、削除、取得するメソッド、およびユーザーがロールに割り当てられているかどうかを確認するメソッドが含まれています。It contains methods to add, remove, and retrieve a user's roles, and a method to check if a user is assigned to a role.
  • IUserPasswordStoreIUserPasswordStore
    IUserPasswordStore < tuser > インターフェイスは、ハッシュされたパスワードを保持するために実装するメソッドを定義します。The IUserPasswordStore<TUser> interface defines the methods you implement to persist hashed passwords. ハッシュされたパスワードを取得および設定するためのメソッドと、ユーザーがパスワードを設定したかどうかを示すメソッドが含まれています。It contains methods for getting and setting the hashed password, and a method that indicates whether the user has set a password.
  • IUserSecurityStampStoreIUserSecurityStampStore
    IUserSecurityStampStore < tuser > インターフェイスでは、ユーザーのアカウント情報が変更されたかどうかを示すセキュリティスタンプを使用するために実装するメソッドを定義します。The IUserSecurityStampStore<TUser> interface defines the methods you implement to use a security stamp for indicating whether the user's account information has changed. このスタンプは、ユーザーがパスワードを変更したとき、またはログインを追加または削除したときに更新されます。This stamp is updated when a user changes the password, or adds or removes logins. セキュリティスタンプを取得および設定するためのメソッドが含まれています。It contains methods for getting and setting the security stamp.
  • IUserTwoFactorStoreIUserTwoFactorStore
    IUserTwoFactorStore < tuser > インターフェイスでは、2要素認証をサポートするために実装するメソッドを定義します。The IUserTwoFactorStore<TUser> interface defines the methods you implement to support two factor authentication. これには、ユーザーに対して2要素認証を有効にするかどうかを取得および設定するためのメソッドが含まれています。It contains methods for getting and setting whether two factor authentication is enabled for a user.
  • IUserPhoneNumberStoreIUserPhoneNumberStore
    IUserPhoneNumberStore < tuser > インターフェイスでは、ユーザーの電話番号を格納するために実装するメソッドを定義します。The IUserPhoneNumberStore<TUser> interface defines the methods you implement to store user phone numbers. 電話番号を取得して設定するためのメソッド、および電話番号を確認する方法が含まれています。It contains methods for getting and setting the phone number and whether the phone number is confirmed.
  • IUserEmailStoreIUserEmailStore
    IUserEmailStore < tuser > インターフェイスでは、ユーザーの電子メールアドレスを格納するために実装するメソッドを定義します。The IUserEmailStore<TUser> interface defines the methods you implement to store user email addresses. このファイルには、電子メールアドレスを取得および設定するためのメソッドと、電子メールを確認するかどうかが含まれています。It contains methods for getting and setting the email address and whether the email is confirmed.
  • IUserLockoutStoreIUserLockoutStore
    IUserLockoutStore < tuser > インターフェイスは、アカウントのロックに関する情報を格納するために実装するメソッドを定義します。The IUserLockoutStore<TUser> interface defines the methods you implement to store information about locking an account. 失敗したアクセス試行とロックアウトを追跡するメソッドが含まれています。It contains methods for tracking failed access attempts and lockouts.
  • IQueryableUserStoreIQueryableUserStore
    Iqueryableuserstore < tuser > インターフェイスは、クエリ可能なユーザーストアを提供するために実装するメンバーを定義します。The IQueryableUserStore<TUser> interface defines the members you implement to provide a queryable user store.

アプリケーションで必要なインターフェイスだけを実装します。You implement only the interfaces that are needed in your app. 次に例を示します。For example:

public class UserStore : IUserStore<IdentityUser>,
                         IUserClaimStore<IdentityUser>,
                         IUserLoginStore<IdentityUser>,
                         IUserRoleStore<IdentityUser>,
                         IUserPasswordStore<IdentityUser>,
                         IUserSecurityStampStore<IdentityUser>
{
    // interface implementations not shown
}

IdentityUserClaim、 Identity userclaim、および Identity UserRoleIdentityUserClaim, IdentityUserLogin, and IdentityUserRole

名前空間には、 Microsoft.AspNet.Identity.EntityFramework Identity userclaim Identity userclaim、および Identity UserRoleクラスの実装が含まれています。The Microsoft.AspNet.Identity.EntityFramework namespace contains implementations of the IdentityUserClaim, IdentityUserLogin, and IdentityUserRole classes. これらの機能を使用している場合は、これらのクラスの独自のバージョンを作成し、アプリのプロパティを定義することができます。If you are using these features, you may want to create your own versions of these classes and define the properties for your app. ただし、基本操作 (ユーザーの要求の追加や削除など) を実行するときに、これらのエンティティをメモリに読み込まない方が効率的な場合もあります。However, sometimes it's more efficient to not load these entities into memory when performing basic operations (such as adding or removing a user's claim). 代わりに、バックエンドストアクラスは、データソースでこれらの操作を直接実行できます。Instead, the backend store classes can execute these operations directly on the data source. たとえば、メソッドは、メソッドを呼び出して、 UserStore.GetClaimsAsync userClaimTable.FindByUserId(user.Id) そのテーブルに対してクエリを直接実行し、クレームの一覧を返すことができます。For example, the UserStore.GetClaimsAsync method can call the userClaimTable.FindByUserId(user.Id) method to execute a query on that table directly and return a list of claims.

ロールクラスをカスタマイズするCustomize the role class

ロールストレージプロバイダーを実装する場合は、カスタムロールの種類を作成できます。When implementing a role storage provider, you can create a custom role type. 特定のインターフェイスを実装する必要はありませんが、が必要であり、 Id 通常はプロパティを持つ必要があり Name ます。It need not implement a particular interface, but it must have an Id and typically it will have a Name property.

ロールクラスの例を次に示します。The following is an example role class:

using System;

namespace CustomIdentityProviderSample.CustomProvider
{
    public class ApplicationRole
    {
        public Guid Id { get; set; } = Guid.NewGuid();
        public string Name { get; set; }
    }
}

ロールストアをカスタマイズするCustomize the role store

RoleStoreロールに対するすべてのデータ操作のメソッドを提供するクラスを作成できます。You can create a RoleStore class that provides the methods for all data operations on roles. このクラスは、 Rolestore < trole > クラスに相当します。This class is equivalent to the RoleStore<TRole> class. クラスで RoleStore は、および必要に応じてインターフェイスを実装し IRoleStore<TRole> IQueryableRoleStore<TRole> ます。In the RoleStore class, you implement the IRoleStore<TRole> and optionally the IQueryableRoleStore<TRole> interface.

  • IRoleStore < trole>IRoleStore<TRole>
    Irolestore < trole > インターフェイスは、ロールストアクラスに実装するメソッドを定義します。The IRoleStore<TRole> interface defines the methods to implement in the role store class. これには、ロールの作成、更新、削除、および取得を行うためのメソッドが含まれています。It contains methods for creating, updating, deleting, and retrieving roles.
  • RoleStore < trole>RoleStore<TRole>
    カスタマイズするには RoleStore 、インターフェイスを実装するクラスを作成し IRoleStore<TRole> ます。To customize RoleStore, create a class that implements the IRoleStore<TRole> interface.

新しい記憶域プロバイダーを使用するようにアプリを再構成するReconfigure app to use a new storage provider

ストレージプロバイダーを実装したら、それを使用するようにアプリを構成します。Once you have implemented a storage provider, you configure your app to use it. アプリで既定のプロバイダーが使用されている場合は、カスタムプロバイダーに置き換えます。If your app used the default provider, replace it with your custom provider.

  1. Microsoft.AspNetCore.EntityFramework.IdentityNuGet パッケージを削除します。Remove the Microsoft.AspNetCore.EntityFramework.Identity NuGet package.
  2. ストレージプロバイダーが別のプロジェクトまたはパッケージに存在する場合は、その記憶域プロバイダーへの参照を追加します。If the storage provider resides in a separate project or package, add a reference to it.
  3. へのすべての参照を、 Microsoft.AspNetCore.EntityFramework.Identity ストレージプロバイダーの名前空間の using ステートメントに置き換えます。Replace all references to Microsoft.AspNetCore.EntityFramework.Identity with a using statement for the namespace of your storage provider.
  4. メソッドで、 ConfigureServices AddIdentity カスタム型を使用するようにメソッドを変更します。In the ConfigureServices method, change the AddIdentity method to use your custom types. この目的のために独自の拡張メソッドを作成できます。You can create your own extension methods for this purpose. 例については、「 Identity ServiceCollectionExtensions 」を参照してください。See IdentityServiceCollectionExtensions for an example.
  5. ロールを使用している場合は、 RoleManager クラスを使用するようにを更新し RoleStore ます。If you are using Roles, update the RoleManager to use your RoleStore class.
  6. 接続文字列と資格情報をアプリの構成に更新します。Update the connection string and credentials to your app's configuration.

例:Example:

public void ConfigureServices(IServiceCollection services)
{
    // Add identity types
    services.AddIdentity<ApplicationUser, ApplicationRole>()
        .AddDefaultTokenProviders();

    // Identity Services
    services.AddTransient<IUserStore<ApplicationUser>, CustomUserStore>();
    services.AddTransient<IRoleStore<ApplicationRole>, CustomRoleStore>();
    string connectionString = Configuration.GetConnectionString("DefaultConnection");
    services.AddTransient<SqlConnection>(e => new SqlConnection(connectionString));
    services.AddTransient<DapperUsersTable>();

    // additional configuration
}

リファレンスReferences