Identity ASP.NET Core でのモデルのカスタマイズIdentity model customization in ASP.NET Core

Arthur ヴィッカースBy Arthur Vickers

ASP.NET Core Identity ASP.NET Core アプリでユーザーアカウントを管理および格納するためのフレームワークを提供します。ASP.NET Core Identity provides a framework for managing and storing user accounts in ASP.NET Core apps. Identity は、認証メカニズムとして 個々のユーザーアカウント が選択されたときにプロジェクトに追加されます。Identity is added to your project when Individual User Accounts is selected as the authentication mechanism. 既定では、は Identity Entity Framework (EF) コアデータモデルを使用します。By default, Identity makes use of an Entity Framework (EF) Core data model. この記事では、モデルをカスタマイズする方法について説明し Identity ます。This article describes how to customize the Identity model.

Identity および EF Core 移行Identity and EF Core Migrations

モデルを調べる前に、 Identity EF Core の移行 を使用してデータベースを作成および更新する方法を理解しておくと役に立ちます。Before examining the model, it's useful to understand how Identity works with EF Core Migrations to create and update a database. 最上位レベルでは、プロセスは次のようになります。At the top level, the process is:

  1. コードでデータモデルを定義または更新します。Define or update a data model in code.
  2. このモデルをデータベースに適用できる変更に変換するには、移行を追加します。Add a Migration to translate this model into changes that can be applied to the database.
  3. 移行によって意図が正しく表現されていることを確認します。Check that the Migration correctly represents your intentions.
  4. モデルと同期するようにデータベースを更新するには、移行を適用します。Apply the Migration to update the database to be in sync with the model.
  5. 手順 1. ~ 4. を繰り返して、モデルをさらに調整し、データベースを同期させます。Repeat steps 1 through 4 to further refine the model and keep the database in sync.

移行を追加して適用するには、次のいずれかの方法を使用します。Use one of the following approaches to add and apply Migrations:

  • Visual Studio を使用している場合は、[ パッケージマネージャーコンソール (PMC)] ウィンドウ。The Package Manager Console (PMC) window if using Visual Studio. 詳細については、「 EF CORE PMC ツール」を参照してください。For more information, see EF Core PMC tools.
  • コマンドラインを使用している場合は、.NET Core CLI ます。The .NET Core CLI if using the command line. 詳細については、「 EF Core .net コマンドラインツール」を参照してください。For more information, see EF Core .NET command line tools.
  • アプリの実行時に、エラーページの [ 移行の適用 ] ボタンをクリックします。Clicking the Apply Migrations button on the error page when the app is run.

ASP.NET Core には、開発時エラーページハンドラーがあります。ASP.NET Core has a development-time error page handler. ハンドラーは、アプリの実行時に移行を適用できます。The handler can apply migrations when the app is run. 実稼働アプリでは、通常、移行から SQL スクリプトを生成し、制御されたアプリとデータベースの配置の一部としてデータベースの変更をデプロイします。Production apps typically generate SQL scripts from the migrations and deploy database changes as part of a controlled app and database deployment.

を使用する新しいアプリを作成すると Identity 、上記の手順 1. と 2. は既に完了しています。When a new app using Identity is created, steps 1 and 2 above have already been completed. つまり、初期データモデルが既に存在し、初期移行がプロジェクトに追加されています。That is, the initial data model already exists, and the initial migration has been added to the project. 初期移行は、引き続きデータベースに適用する必要があります。The initial migration still needs to be applied to the database. 最初の移行は、次のいずれかの方法を使用して適用できます。The initial migration can be applied via one of the following approaches:

  • Update-DatabasePMC でを実行します。Run Update-Database in PMC.
  • dotnet ef database updateコマンドシェルでを実行します。Run dotnet ef database update in a command shell.
  • アプリの実行時に、エラーページの [ 移行の適用 ] ボタンをクリックします。Click the Apply Migrations button on the error page when the app is run.

モデルが変更されたときに、上記の手順を繰り返します。Repeat the preceding steps as changes are made to the model.

IdentityモデルThe Identity model

エンティティの種類Entity types

モデルは、 Identity 次のエンティティ型で構成されます。The Identity model consists of the following entity types.

エンティティの種類Entity type [説明]Description
User ユーザーを表します。Represents the user.
Role ロールを表します。Represents a role.
UserClaim ユーザーが所有するクレームを表します。Represents a claim that a user possesses.
UserToken ユーザーの認証トークンを表します。Represents an authentication token for a user.
UserLogin ユーザーをログインに関連付けます。Associates a user with a login.
RoleClaim ロール内のすべてのユーザーに付与されるクレームを表します。Represents a claim that's granted to all users within a role.
UserRole ユーザーとロールを関連付ける結合エンティティ。A join entity that associates users and roles.

エンティティ型のリレーションシップEntity type relationships

エンティティ型は、次の方法で相互に関連付けられます。The entity types are related to each other in the following ways:

  • 各には User 多くのを含めることができ UserClaims ます。Each User can have many UserClaims.
  • 各には User 多くのを含めることができ UserLogins ます。Each User can have many UserLogins.
  • 各には User 多くのを含めることができ UserTokens ます。Each User can have many UserTokens.
  • それぞれに Role 関連付けることができ RoleClaims ます。Each Role can have many associated RoleClaims.
  • それぞれに User 関連付けることができ Roles 、各を Role 多くのに関連付けることができ Users ます。Each User can have many associated Roles, and each Role can be associated with many Users. これは、データベース内の結合テーブルを必要とする多対多リレーションシップです。This is a many-to-many relationship that requires a join table in the database. 結合テーブルは、エンティティによって表され UserRole ます。The join table is represented by the UserRole entity.

既定のモデル構成Default model configuration

Identityモデルを構成して使用するために Dbcontextから継承する多くの コンテキストクラス を定義します。Identity defines many context classes that inherit from DbContext to configure and use the model. この構成は、コンテキストクラスのOnmodelcreatingメソッドでEF CORE Code First Fluent APIを使用して行います。This configuration is done using the EF Core Code First Fluent API in the OnModelCreating method of the context class. 既定の構成は次のとおりです。The default configuration is:

builder.Entity<TUser>(b =>
{
    // Primary key
    b.HasKey(u => u.Id);

    // Indexes for "normalized" username and email, to allow efficient lookups
    b.HasIndex(u => u.NormalizedUserName).HasName("UserNameIndex").IsUnique();
    b.HasIndex(u => u.NormalizedEmail).HasName("EmailIndex");

    // Maps to the AspNetUsers table
    b.ToTable("AspNetUsers");

    // A concurrency token for use with the optimistic concurrency checking
    b.Property(u => u.ConcurrencyStamp).IsConcurrencyToken();

    // Limit the size of columns to use efficient database types
    b.Property(u => u.UserName).HasMaxLength(256);
    b.Property(u => u.NormalizedUserName).HasMaxLength(256);
    b.Property(u => u.Email).HasMaxLength(256);
    b.Property(u => u.NormalizedEmail).HasMaxLength(256);

    // The relationships between User and other entity types
    // Note that these relationships are configured with no navigation properties

    // Each User can have many UserClaims
    b.HasMany<TUserClaim>().WithOne().HasForeignKey(uc => uc.UserId).IsRequired();

    // Each User can have many UserLogins
    b.HasMany<TUserLogin>().WithOne().HasForeignKey(ul => ul.UserId).IsRequired();

    // Each User can have many UserTokens
    b.HasMany<TUserToken>().WithOne().HasForeignKey(ut => ut.UserId).IsRequired();

    // Each User can have many entries in the UserRole join table
    b.HasMany<TUserRole>().WithOne().HasForeignKey(ur => ur.UserId).IsRequired();
});

builder.Entity<TUserClaim>(b =>
{
    // Primary key
    b.HasKey(uc => uc.Id);

    // Maps to the AspNetUserClaims table
    b.ToTable("AspNetUserClaims");
});

builder.Entity<TUserLogin>(b =>
{
    // Composite primary key consisting of the LoginProvider and the key to use
    // with that provider
    b.HasKey(l => new { l.LoginProvider, l.ProviderKey });

    // Limit the size of the composite key columns due to common DB restrictions
    b.Property(l => l.LoginProvider).HasMaxLength(128);
    b.Property(l => l.ProviderKey).HasMaxLength(128);

    // Maps to the AspNetUserLogins table
    b.ToTable("AspNetUserLogins");
});

builder.Entity<TUserToken>(b =>
{
    // Composite primary key consisting of the UserId, LoginProvider and Name
    b.HasKey(t => new { t.UserId, t.LoginProvider, t.Name });

    // Limit the size of the composite key columns due to common DB restrictions
    b.Property(t => t.LoginProvider).HasMaxLength(maxKeyLength);
    b.Property(t => t.Name).HasMaxLength(maxKeyLength);

    // Maps to the AspNetUserTokens table
    b.ToTable("AspNetUserTokens");
});

builder.Entity<TRole>(b =>
{
    // Primary key
    b.HasKey(r => r.Id);

    // Index for "normalized" role name to allow efficient lookups
    b.HasIndex(r => r.NormalizedName).HasName("RoleNameIndex").IsUnique();

    // Maps to the AspNetRoles table
    b.ToTable("AspNetRoles");

    // A concurrency token for use with the optimistic concurrency checking
    b.Property(r => r.ConcurrencyStamp).IsConcurrencyToken();

    // Limit the size of columns to use efficient database types
    b.Property(u => u.Name).HasMaxLength(256);
    b.Property(u => u.NormalizedName).HasMaxLength(256);

    // The relationships between Role and other entity types
    // Note that these relationships are configured with no navigation properties

    // Each Role can have many entries in the UserRole join table
    b.HasMany<TUserRole>().WithOne().HasForeignKey(ur => ur.RoleId).IsRequired();

    // Each Role can have many associated RoleClaims
    b.HasMany<TRoleClaim>().WithOne().HasForeignKey(rc => rc.RoleId).IsRequired();
});

builder.Entity<TRoleClaim>(b =>
{
    // Primary key
    b.HasKey(rc => rc.Id);

    // Maps to the AspNetRoleClaims table
    b.ToTable("AspNetRoleClaims");
});

builder.Entity<TUserRole>(b =>
{
    // Primary key
    b.HasKey(r => new { r.UserId, r.RoleId });

    // Maps to the AspNetUserRoles table
    b.ToTable("AspNetUserRoles");
});

モデルのジェネリック型Model generic types

Identity 上に示した各エンティティ型に対して、既定の 共通言語ランタイム (CLR) 型を定義します。Identity defines default Common Language Runtime (CLR) types for each of the entity types listed above. これらの型のすべてにプレフィックスが付いてい Identity ます。These types are all prefixed with Identity :

  • IdentityUser
  • IdentityRole
  • IdentityUserClaim
  • IdentityUserToken
  • IdentityUserLogin
  • IdentityRoleClaim
  • IdentityUserRole

これらの型を直接使用するのではなく、アプリケーション独自の型の基底クラスとして型を使用できます。Rather than using these types directly, the types can be used as base classes for the app's own types. DbContextによって定義さ Identity れるクラスはジェネリックであるため、モデル内の1つ以上のエンティティ型に異なる CLR 型を使用できます。The DbContext classes defined by Identity are generic, such that different CLR types can be used for one or more of the entity types in the model. これらのジェネリック型を使用すると、 User 主キー (PK) データ型を変更することもできます。These generic types also allow the User primary key (PK) data type to be changed.

ロールのサポートを使用する場合は Identity 、 IdentityDbContext クラスを使用する必要があります。When using Identity with support for roles, an IdentityDbContext class should be used. 次に例を示します。For example:

// Uses all the built-in Identity types
// Uses `string` as the key type
public class IdentityDbContext
    : IdentityDbContext<IdentityUser, IdentityRole, string>
{
}

// Uses the built-in Identity types except with a custom User type
// Uses `string` as the key type
public class IdentityDbContext<TUser>
    : IdentityDbContext<TUser, IdentityRole, string>
        where TUser : IdentityUser
{
}

// Uses the built-in Identity types except with custom User and Role types
// The key type is defined by TKey
public class IdentityDbContext<TUser, TRole, TKey> : IdentityDbContext<
    TUser, TRole, TKey, IdentityUserClaim<TKey>, IdentityUserRole<TKey>,
    IdentityUserLogin<TKey>, IdentityRoleClaim<TKey>, IdentityUserToken<TKey>>
        where TUser : IdentityUser<TKey>
        where TRole : IdentityRole<TKey>
        where TKey : IEquatable<TKey>
{
}

// No built-in Identity types are used; all are specified by generic arguments
// The key type is defined by TKey
public abstract class IdentityDbContext<
    TUser, TRole, TKey, TUserClaim, TUserRole, TUserLogin, TRoleClaim, TUserToken>
    : IdentityUserContext<TUser, TKey, TUserClaim, TUserLogin, TUserToken>
         where TUser : IdentityUser<TKey>
         where TRole : IdentityRole<TKey>
         where TKey : IEquatable<TKey>
         where TUserClaim : IdentityUserClaim<TKey>
         where TUserRole : IdentityUserRole<TKey>
         where TUserLogin : IdentityUserLogin<TKey>
         where TRoleClaim : IdentityRoleClaim<TKey>
         where TUserToken : IdentityUserToken<TKey>

Identityロールなし (要求のみ) を使用することもできます。この場合、 IdentityUserContext<TUser> クラスを使用する必要があります。It's also possible to use Identity without roles (only claims), in which case an IdentityUserContext<TUser> class should be used:

// Uses the built-in non-role Identity types except with a custom User type
// Uses `string` as the key type
public class IdentityUserContext<TUser>
    : IdentityUserContext<TUser, string>
        where TUser : IdentityUser
{
}

// Uses the built-in non-role Identity types except with a custom User type
// The key type is defined by TKey
public class IdentityUserContext<TUser, TKey> : IdentityUserContext<
    TUser, TKey, IdentityUserClaim<TKey>, IdentityUserLogin<TKey>,
    IdentityUserToken<TKey>>
        where TUser : IdentityUser<TKey>
        where TKey : IEquatable<TKey>
{
}

// No built-in Identity types are used; all are specified by generic arguments, with no roles
// The key type is defined by TKey
public abstract class IdentityUserContext<
    TUser, TKey, TUserClaim, TUserLogin, TUserToken> : DbContext
        where TUser : IdentityUser<TKey>
        where TKey : IEquatable<TKey>
        where TUserClaim : IdentityUserClaim<TKey>
        where TUserLogin : IdentityUserLogin<TKey>
        where TUserToken : IdentityUserToken<TKey>
{
}

モデルをカスタマイズするCustomize the model

モデルのカスタマイズの開始点は、適切なコンテキスト型から派生することです。The starting point for model customization is to derive from the appropriate context type. モデルのジェネリック型 」を参照してください。See the Model generic types section. このコンテキストの種類は通常と呼ばれ、 ApplicationDbContext ASP.NET Core テンプレートによって作成されます。This context type is customarily called ApplicationDbContext and is created by the ASP.NET Core templates.

このコンテキストは、次の2つの方法でモデルを構成するために使用されます。The context is used to configure the model in two ways:

  • ジェネリック型パラメーターのエンティティ型とキー型を提供します。Supplying entity and key types for the generic type parameters.
  • をオーバーライドし OnModelCreating て、これらの型のマッピングを変更します。Overriding OnModelCreating to modify the mapping of these types.

をオーバーライドする場合は OnModelCreating 、最初にを base.OnModelCreating 呼び出す必要があります。次に、オーバーライドする構成を呼び出す必要があります。When overriding OnModelCreating, base.OnModelCreating should be called first; the overriding configuration should be called next. EF Core は、一般に、構成のための最後の1つの wins ポリシーを持っています。EF Core generally has a last-one-wins policy for configuration. たとえば、 ToTable エンティティ型のメソッドが最初に1つのテーブル名で呼び出され、後で別のテーブル名を使用して呼び出された場合、2番目の呼び出しのテーブル名が使用されます。For example, if the ToTable method for an entity type is called first with one table name and then again later with a different table name, the table name in the second call is used.

カスタムユーザーデータCustom user data

カスタムユーザーデータ は、から継承することによってサポートされ IdentityUser ます。Custom user data is supported by inheriting from IdentityUser. この型には、次のような名前が付いてい ApplicationUser ます。It's customary to name this type ApplicationUser:

public class ApplicationUser : IdentityUser
{
    public string CustomTag { get; set; }
}

この型は、 ApplicationUser コンテキストの汎用引数として使用します。Use the ApplicationUser type as a generic argument for the context:

public class ApplicationDbContext : IdentityDbContext<ApplicationUser>
{
    public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options)
        : base(options)
    {
    }

    protected override void OnModelCreating(ModelBuilder builder)
    {
        base.OnModelCreating(builder);
    }
}

クラスでオーバーライドする必要はありません OnModelCreating ApplicationDbContextThere's no need to override OnModelCreating in the ApplicationDbContext class. EF Core は、 CustomTag 規則に従ってプロパティをマップします。EF Core maps the CustomTag property by convention. ただし、新しい列を作成するには、データベースを更新する必要があり CustomTag ます。However, the database needs to be updated to create a new CustomTag column. 列を作成するには、移行を追加し、「」 Identity および「EF Core の移行」の説明に従ってデータベースを更新します。To create the column, add a migration, and then update the database as described in Identity and EF Core Migrations.

Pages/Shared/_LoginPartial を更新し、を IdentityUser に置き換え ApplicationUser ます。Update Pages/Shared/_LoginPartial.cshtml and replace IdentityUser with ApplicationUser:

@using Microsoft.AspNetCore.Identity
@using WebApp1.Areas.Identity.Data
@inject SignInManager<ApplicationUser> SignInManager
@inject UserManager<ApplicationUser> UserManager

区分/ Identity / Identity HostingStartup.cs を更新するか Startup.ConfigureServices 、を IdentityUser に置き換え ApplicationUser ます。Update Areas/Identity/IdentityHostingStartup.cs or Startup.ConfigureServices and replace IdentityUser with ApplicationUser.

services.AddIdentity<ApplicationUser>()
        .AddEntityFrameworkStores<ApplicationDbContext>()
        .AddDefaultUI();

ASP.NET Core 2.1 以降では、 Identity がクラスライブラリとして提供され Razor ます。In ASP.NET Core 2.1 or later, Identity is provided as a Razor Class Library. 詳細については、「IdentityASP.NET Core プロジェクトでのスキャフォールディング」を参照してください。For more information, see IdentityASP.NET Core プロジェクトでのスキャフォールディング. そのため、上記のコードでは、を呼び出す必要があり AddDefaultUI ます。Consequently, the preceding code requires a call to AddDefaultUI. Scaffolder を Identity 使用してファイルをプロジェクトに追加した場合は、への呼び出しを削除し Identity AddDefaultUI ます。If the Identity scaffolder was used to add Identity files to the project, remove the call to AddDefaultUI. 詳細については、次をご覧ください。For more information, see:

主キーの種類を変更するChange the primary key type

データベースを作成した後に PK 列のデータ型を変更すると、多くのデータベースシステムで問題が発生します。A change to the PK column's data type after the database has been created is problematic on many database systems. PK を変更するには、通常、テーブルを削除してから再作成する必要があります。Changing the PK typically involves dropping and re-creating the table. そのため、データベースの作成時に、初期移行でキーの種類を指定する必要があります。Therefore, key types should be specified in the initial migration when the database is created.

PK の種類を変更するには、次の手順に従います。Follow these steps to change the PK type:

  1. PK が変更される前にデータベースが作成された場合は、 Drop-Database (PMC) または dotnet ef database drop (.NET Core CLI) を実行して削除します。If the database was created before the PK change, run Drop-Database (PMC) or dotnet ef database drop (.NET Core CLI) to delete it.

  2. データベースの削除を確認した後、 Remove-Migration (PMC) または (.NET Core CLI) を使用して最初の移行を削除し dotnet ef migrations remove ます。After confirming deletion of the database, remove the initial migration with Remove-Migration (PMC) or dotnet ef migrations remove (.NET Core CLI).

  3. ApplicationDbContextから派生するようにクラスを更新 IdentityDbContext<TUser,TRole,TKey> します。Update the ApplicationDbContext class to derive from IdentityDbContext<TUser,TRole,TKey>. の新しいキーの種類を指定し TKey ます。Specify the new key type for TKey. たとえば、キーの種類を使用するには、次のように Guid 入力します。For example, to use a Guid key type:

    public class ApplicationDbContext
        : IdentityDbContext<IdentityUser<Guid>, IdentityRole<Guid>, Guid>
    {
        public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options)
            : base(options)
        {
        }
    }
    

    前のコードでは、ジェネリッククラス IdentityUser<TKey> とは、 IdentityRole<TKey> 新しいキー型を使用するように指定する必要があります。In the preceding code, the generic classes IdentityUser<TKey> and IdentityRole<TKey> must be specified to use the new key type.

    前のコードでは、ジェネリッククラス IdentityUser<TKey> とは、 IdentityRole<TKey> 新しいキー型を使用するように指定する必要があります。In the preceding code, the generic classes IdentityUser<TKey> and IdentityRole<TKey> must be specified to use the new key type.

    Startup.ConfigureServices 汎用ユーザーを使用するには、次のように更新する必要があります。Startup.ConfigureServices must be updated to use the generic user:

    services.AddDefaultIdentity<IdentityUser<Guid>>()
            .AddEntityFrameworkStores<ApplicationDbContext>();
    
    services.AddIdentity<IdentityUser<Guid>, IdentityRole>()
            .AddEntityFrameworkStores<ApplicationDbContext>()
            .AddDefaultTokenProviders();
    
    services.AddIdentity<IdentityUser<Guid>, IdentityRole>()
            .AddEntityFrameworkStores<ApplicationDbContext, Guid>()
            .AddDefaultTokenProviders();
    
  4. カスタムクラスが使用されている場合は ApplicationUser 、継承元のクラスを更新し IdentityUser ます。If a custom ApplicationUser class is being used, update the class to inherit from IdentityUser. 次に例を示します。For example:

    using System;
    using Microsoft.AspNetCore.Identity.EntityFrameworkCore;
    
    public class ApplicationUser : IdentityUser<Guid>
    {
        public string CustomTag { get; set; }        
    }
    
    using System;
    using Microsoft.AspNetCore.Identity;
    
    public class ApplicationUser : IdentityUser<Guid>
    {
        public string CustomTag { get; set; }
    }
    

    ApplicationDbContextカスタムクラスを参照するように更新し ApplicationUser ます。Update ApplicationDbContext to reference the custom ApplicationUser class:

    public class ApplicationDbContext
        : IdentityDbContext<ApplicationUser, IdentityRole<Guid>, Guid>
    {
        public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options)
            : base(options)
        {
        }
    }
    

    でサービスを追加するときに、カスタムデータベースコンテキストクラスを登録し Identity Startup.ConfigureServices ます。Register the custom database context class when adding the Identity service in Startup.ConfigureServices:

    services.AddIdentity<ApplicationUser>()
            .AddEntityFrameworkStores<ApplicationDbContext>()
            .AddDefaultUI()
            .AddDefaultTokenProviders();
    

    主キーのデータ型は、 Dbcontext オブジェクトを分析することによって推論されます。The primary key's data type is inferred by analyzing the DbContext object.

    ASP.NET Core 2.1 以降では、 Identity がクラスライブラリとして提供され Razor ます。In ASP.NET Core 2.1 or later, Identity is provided as a Razor Class Library. 詳細については、「IdentityASP.NET Core プロジェクトでのスキャフォールディング」を参照してください。For more information, see IdentityASP.NET Core プロジェクトでのスキャフォールディング. そのため、上記のコードでは、を呼び出す必要があり AddDefaultUI ます。Consequently, the preceding code requires a call to AddDefaultUI. Scaffolder を Identity 使用してファイルをプロジェクトに追加した場合は、への呼び出しを削除し Identity AddDefaultUI ます。If the Identity scaffolder was used to add Identity files to the project, remove the call to AddDefaultUI.

    services.AddIdentity<ApplicationUser, IdentityRole>()
            .AddEntityFrameworkStores<ApplicationDbContext>()
            .AddDefaultTokenProviders();
    

    主キーのデータ型は、 Dbcontext オブジェクトを分析することによって推論されます。The primary key's data type is inferred by analyzing the DbContext object.

    services.AddIdentity<ApplicationUser, IdentityRole>()
            .AddEntityFrameworkStores<ApplicationDbContext, Guid>()
            .AddDefaultTokenProviders();
    

    メソッドは、 AddEntityFrameworkStores TKey 主キーのデータ型を示す型を受け取ります。The AddEntityFrameworkStores method accepts a TKey type indicating the primary key's data type.

  5. カスタムクラスが使用されている場合は ApplicationRole 、継承元のクラスを更新し IdentityRole<TKey> ます。If a custom ApplicationRole class is being used, update the class to inherit from IdentityRole<TKey>. 次に例を示します。For example:

    using System;
    using Microsoft.AspNetCore.Identity;
    
    public class ApplicationRole : IdentityRole<Guid>
    {
        public string Description { get; set; }
    }
    

    ApplicationDbContextカスタムクラスを参照するように更新し ApplicationRole ます。Update ApplicationDbContext to reference the custom ApplicationRole class. たとえば、次のクラスはカスタム ApplicationUser とカスタムを参照し ApplicationRole ます。For example, the following class references a custom ApplicationUser and a custom ApplicationRole:

    using System;
    using Microsoft.AspNetCore.Identity.EntityFrameworkCore;
    using Microsoft.EntityFrameworkCore;
    
    public class ApplicationDbContext :
        IdentityDbContext<ApplicationUser, ApplicationRole, Guid>
    {
        public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options)
            : base(options)
        {
        }
    }
    

    でサービスを追加するときに、カスタムデータベースコンテキストクラスを登録し Identity Startup.ConfigureServices ます。Register the custom database context class when adding the Identity service in Startup.ConfigureServices:

    public void ConfigureServices(IServiceCollection services)
    {
        services.Configure<CookiePolicyOptions>(options =>
        {
            options.CheckConsentNeeded = context => true;
            options.MinimumSameSitePolicy = SameSiteMode.None;
        });
    
        services.AddDbContext<ApplicationDbContext>(options =>
            options.UseSqlServer(
                Configuration.GetConnectionString("DefaultConnection")));
    
        services.AddIdentity<ApplicationUser, ApplicationRole>()
                .AddEntityFrameworkStores<ApplicationDbContext>()
                .AddDefaultUI()
                .AddDefaultTokenProviders();
    
        services.AddMvc()
                .SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
    }
    

    主キーのデータ型は、 Dbcontext オブジェクトを分析することによって推論されます。The primary key's data type is inferred by analyzing the DbContext object.

    ASP.NET Core 2.1 以降では、 Identity がクラスライブラリとして提供され Razor ます。In ASP.NET Core 2.1 or later, Identity is provided as a Razor Class Library. 詳細については、「IdentityASP.NET Core プロジェクトでのスキャフォールディング」を参照してください。For more information, see IdentityASP.NET Core プロジェクトでのスキャフォールディング. そのため、上記のコードでは、を呼び出す必要があり AddDefaultUI ます。Consequently, the preceding code requires a call to AddDefaultUI. Scaffolder を Identity 使用してファイルをプロジェクトに追加した場合は、への呼び出しを削除し Identity AddDefaultUI ます。If the Identity scaffolder was used to add Identity files to the project, remove the call to AddDefaultUI.

    using System;
    using Microsoft.AspNetCore.Identity.EntityFrameworkCore;
    using Microsoft.EntityFrameworkCore;
    
    public class ApplicationDbContext : 
        IdentityDbContext<ApplicationUser, ApplicationRole, Guid>
    {
        public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options)
            : base(options)
        {
        }
    }
    

    でサービスを追加するときに、カスタムデータベースコンテキストクラスを登録し Identity Startup.ConfigureServices ます。Register the custom database context class when adding the Identity service in Startup.ConfigureServices:

    public void ConfigureServices(IServiceCollection services)
    {
        services.AddDbContext<ApplicationDbContext>(options =>
            options.UseSqlServer(
                Configuration.GetConnectionString("DefaultConnection")));
    
        services.AddIdentity<ApplicationUser, ApplicationRole>()
                .AddEntityFrameworkStores<ApplicationDbContext>()
                .AddDefaultTokenProviders();
    
        services.AddMvc()
            .AddRazorPagesOptions(options =>
            {
                options.Conventions.AuthorizeFolder("/Account/Manage");
                options.Conventions.AuthorizePage("/Account/Logout");
            });
    
        services.AddSingleton<IEmailSender, EmailSender>();
    }
    

    主キーのデータ型は、 Dbcontext オブジェクトを分析することによって推論されます。The primary key's data type is inferred by analyzing the DbContext object.

    using System;
    using Microsoft.AspNetCore.Identity.EntityFrameworkCore;
    using Microsoft.EntityFrameworkCore;
    
    public class ApplicationDbContext : 
        IdentityDbContext<ApplicationUser, ApplicationRole, Guid>
    {
        public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options)
            : base(options)
        {
        }
    }
    

    でサービスを追加するときに、カスタムデータベースコンテキストクラスを登録し Identity Startup.ConfigureServices ます。Register the custom database context class when adding the Identity service in Startup.ConfigureServices:

    public void ConfigureServices(IServiceCollection services)
    {
        services.AddDbContext<ApplicationDbContext>(options => 
            options.UseSqlServer(
                Configuration.GetConnectionString("DefaultConnection")));
    
        services.AddIdentity<ApplicationUser, ApplicationRole>()
                .AddEntityFrameworkStores<ApplicationDbContext, Guid>()
                .AddDefaultTokenProviders();
    
        services.AddMvc();
    
        services.AddTransient<IEmailSender, AuthMessageSender>();
        services.AddTransient<ISmsSender, AuthMessageSender>();
    }
    

    メソッドは、 AddEntityFrameworkStores TKey 主キーのデータ型を示す型を受け取ります。The AddEntityFrameworkStores method accepts a TKey type indicating the primary key's data type.

ナビゲーションプロパティの追加Add navigation properties

リレーションシップのモデル構成の変更は、他の変更を行うよりも困難になることがあります。Changing the model configuration for relationships can be more difficult than making other changes. 新しい追加のリレーションシップを作成するのではなく、既存のリレーションシップを置き換える必要があります。Care must be taken to replace the existing relationships rather than create new, additional relationships. 特に、変更されたリレーションシップでは、既存のリレーションシップと同じ外部キー (FK) プロパティを指定する必要があります。In particular, the changed relationship must specify the same foreign key (FK) property as the existing relationship. たとえば、との間の Users リレーションシップ UserClaims は、既定では次のように指定されています。For example, the relationship between Users and UserClaims is, by default, specified as follows:

builder.Entity<TUser>(b =>
{
    // Each User can have many UserClaims
    b.HasMany<TUserClaim>()
     .WithOne()
     .HasForeignKey(uc => uc.UserId)
     .IsRequired();
});

このリレーションシップの FK は、プロパティとして指定され UserClaim.UserId ます。The FK for this relationship is specified as the UserClaim.UserId property. HasMany および WithOne は、ナビゲーションプロパティを使用せずにリレーションシップを作成するための引数なしで呼び出されます。HasMany and WithOne are called without arguments to create the relationship without navigation properties.

ApplicationUser関連するをユーザーから参照できるようにするナビゲーションプロパティをに追加し UserClaims ます。Add a navigation property to ApplicationUser that allows associated UserClaims to be referenced from the user:

public class ApplicationUser : IdentityUser
{
    public virtual ICollection<IdentityUserClaim<string>> Claims { get; set; }
}

のは、 TKey IdentityUserClaim<TKey> ユーザーの PK に対して指定された型です。The TKey for IdentityUserClaim<TKey> is the type specified for the PK of users. この場合、 TKeystring 既定値が使用されているためです。In this case, TKey is string because the defaults are being used. エンティティ型の PK 型では ありません UserClaimIt's not the PK type for the UserClaim entity type.

ナビゲーションプロパティが存在するようになったので、次のように構成する必要があり OnModelCreating ます。Now that the navigation property exists, it must be configured in OnModelCreating:

public class ApplicationDbContext : IdentityDbContext<ApplicationUser>
{
    public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options)
        : base(options)
    {
    }

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        base.OnModelCreating(modelBuilder);

        modelBuilder.Entity<ApplicationUser>(b =>
        {
            // Each User can have many UserClaims
            b.HasMany(e => e.Claims)
                .WithOne()
                .HasForeignKey(uc => uc.UserId)
                .IsRequired();
        });
    }
}

リレーションシップは前とまったく同じように構成されていることに注意してください。の呼び出しで指定されたナビゲーションプロパティを使用し HasMany ます。Notice that relationship is configured exactly as it was before, only with a navigation property specified in the call to HasMany.

ナビゲーションプロパティは、データベースではなく EF モデルにのみ存在します。The navigation properties only exist in the EF model, not the database. リレーションシップの FK は変更されていないため、この種のモデルの変更では、データベースを更新する必要はありません。Because the FK for the relationship hasn't changed, this kind of model change doesn't require the database to be updated. これは、変更を行った後に移行を追加することによって確認できます。This can be checked by adding a migration after making the change. Upメソッドと Down メソッドは空です。The Up and Down methods are empty.

すべてのユーザーナビゲーションプロパティを追加するAdd all User navigation properties

次の例では、上のセクションをガイダンスとして使用して、ユーザーのすべてのリレーションシップに対して一方向のナビゲーションプロパティを構成します。Using the section above as guidance, the following example configures unidirectional navigation properties for all relationships on User:

public class ApplicationUser : IdentityUser
{
    public virtual ICollection<IdentityUserClaim<string>> Claims { get; set; }
    public virtual ICollection<IdentityUserLogin<string>> Logins { get; set; }
    public virtual ICollection<IdentityUserToken<string>> Tokens { get; set; }
    public virtual ICollection<IdentityUserRole<string>> UserRoles { get; set; }
}
public class ApplicationDbContext : IdentityDbContext<ApplicationUser>
{
    public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options)
        : base(options)
    {
    }

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        base.OnModelCreating(modelBuilder);

        modelBuilder.Entity<ApplicationUser>(b =>
        {
            // Each User can have many UserClaims
            b.HasMany(e => e.Claims)
                .WithOne()
                .HasForeignKey(uc => uc.UserId)
                .IsRequired();

            // Each User can have many UserLogins
            b.HasMany(e => e.Logins)
                .WithOne()
                .HasForeignKey(ul => ul.UserId)
                .IsRequired();

            // Each User can have many UserTokens
            b.HasMany(e => e.Tokens)
                .WithOne()
                .HasForeignKey(ut => ut.UserId)
                .IsRequired();

            // Each User can have many entries in the UserRole join table
            b.HasMany(e => e.UserRoles)
                .WithOne()
                .HasForeignKey(ur => ur.UserId)
                .IsRequired();
        });
    }
}

ユーザーおよびロールのナビゲーションプロパティの追加Add User and Role navigation properties

次の例では、上のセクションをガイダンスとして使用して、ユーザーとロールのすべてのリレーションシップに対してナビゲーションプロパティを構成します。Using the section above as guidance, the following example configures navigation properties for all relationships on User and Role:

public class ApplicationUser : IdentityUser
{
    public virtual ICollection<IdentityUserClaim<string>> Claims { get; set; }
    public virtual ICollection<IdentityUserLogin<string>> Logins { get; set; }
    public virtual ICollection<IdentityUserToken<string>> Tokens { get; set; }
    public virtual ICollection<ApplicationUserRole> UserRoles { get; set; }
}

public class ApplicationRole : IdentityRole
{
    public virtual ICollection<ApplicationUserRole> UserRoles { get; set; }
}

public class ApplicationUserRole : IdentityUserRole<string>
{
    public virtual ApplicationUser User { get; set; }
    public virtual ApplicationRole Role { get; set; }
}
public class ApplicationDbContext
    : IdentityDbContext<
        ApplicationUser, ApplicationRole, string,
        IdentityUserClaim<string>, ApplicationUserRole, IdentityUserLogin<string>,
        IdentityRoleClaim<string>, IdentityUserToken<string>>
{
    public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options)
        : base(options)
    {
    }

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        base.OnModelCreating(modelBuilder);

        modelBuilder.Entity<ApplicationUser>(b =>
        {
            // Each User can have many UserClaims
            b.HasMany(e => e.Claims)
                .WithOne()
                .HasForeignKey(uc => uc.UserId)
                .IsRequired();

            // Each User can have many UserLogins
            b.HasMany(e => e.Logins)
                .WithOne()
                .HasForeignKey(ul => ul.UserId)
                .IsRequired();

            // Each User can have many UserTokens
            b.HasMany(e => e.Tokens)
                .WithOne()
                .HasForeignKey(ut => ut.UserId)
                .IsRequired();

            // Each User can have many entries in the UserRole join table
            b.HasMany(e => e.UserRoles)
                .WithOne(e => e.User)
                .HasForeignKey(ur => ur.UserId)
                .IsRequired();
        });

        modelBuilder.Entity<ApplicationRole>(b =>
        {
            // Each Role can have many entries in the UserRole join table
            b.HasMany(e => e.UserRoles)
                .WithOne(e => e.Role)
                .HasForeignKey(ur => ur.RoleId)
                .IsRequired();
        });

    }
}

メモ:Notes:

  • この例には、 UserRole ユーザーからロールへの多対多リレーションシップを移動するために必要な join エンティティも含まれています。This example also includes the UserRole join entity, which is needed to navigate the many-to-many relationship from Users to Roles.
  • 型ではなく型が使用されていることを反映するように、ナビゲーションプロパティの型を変更することを忘れないで Application{...} Identity{...} ください。Remember to change the types of the navigation properties to reflect that Application{...} types are now being used instead of Identity{...} types.
  • ジェネリック定義でを使用することを忘れない Application{...}ApplicationContext ください。Remember to use the Application{...} in the generic ApplicationContext definition.

すべてのナビゲーションプロパティの追加Add all navigation properties

次の例では、上のセクションをガイダンスとして使用して、すべてのエンティティ型のすべてのリレーションシップに対してナビゲーションプロパティを構成します。Using the section above as guidance, the following example configures navigation properties for all relationships on all entity types:

public class ApplicationUser : IdentityUser
{
    public virtual ICollection<ApplicationUserClaim> Claims { get; set; }
    public virtual ICollection<ApplicationUserLogin> Logins { get; set; }
    public virtual ICollection<ApplicationUserToken> Tokens { get; set; }
    public virtual ICollection<ApplicationUserRole> UserRoles { get; set; }
}

public class ApplicationRole : IdentityRole
{
    public virtual ICollection<ApplicationUserRole> UserRoles { get; set; }
    public virtual ICollection<ApplicationRoleClaim> RoleClaims { get; set; }
}

public class ApplicationUserRole : IdentityUserRole<string>
{
    public virtual ApplicationUser User { get; set; }
    public virtual ApplicationRole Role { get; set; }
}

public class ApplicationUserClaim : IdentityUserClaim<string>
{
    public virtual ApplicationUser User { get; set; }
}

public class ApplicationUserLogin : IdentityUserLogin<string>
{
    public virtual ApplicationUser User { get; set; }
}

public class ApplicationRoleClaim : IdentityRoleClaim<string>
{
    public virtual ApplicationRole Role { get; set; }
}

public class ApplicationUserToken : IdentityUserToken<string>
{
    public virtual ApplicationUser User { get; set; }
}
public class ApplicationDbContext
    : IdentityDbContext<
        ApplicationUser, ApplicationRole, string,
        ApplicationUserClaim, ApplicationUserRole, ApplicationUserLogin,
        ApplicationRoleClaim, ApplicationUserToken>
{
    public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options)
        : base(options)
    {
    }

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        base.OnModelCreating(modelBuilder);

        modelBuilder.Entity<ApplicationUser>(b =>
        {
            // Each User can have many UserClaims
            b.HasMany(e => e.Claims)
                .WithOne(e => e.User)
                .HasForeignKey(uc => uc.UserId)
                .IsRequired();

            // Each User can have many UserLogins
            b.HasMany(e => e.Logins)
                .WithOne(e => e.User)
                .HasForeignKey(ul => ul.UserId)
                .IsRequired();

            // Each User can have many UserTokens
            b.HasMany(e => e.Tokens)
                .WithOne(e => e.User)
                .HasForeignKey(ut => ut.UserId)
                .IsRequired();

            // Each User can have many entries in the UserRole join table
            b.HasMany(e => e.UserRoles)
                .WithOne(e => e.User)
                .HasForeignKey(ur => ur.UserId)
                .IsRequired();
        });

        modelBuilder.Entity<ApplicationRole>(b =>
        {
            // Each Role can have many entries in the UserRole join table
            b.HasMany(e => e.UserRoles)
                .WithOne(e => e.Role)
                .HasForeignKey(ur => ur.RoleId)
                .IsRequired();

            // Each Role can have many associated RoleClaims
            b.HasMany(e => e.RoleClaims)
                .WithOne(e => e.Role)
                .HasForeignKey(rc => rc.RoleId)
                .IsRequired();
        });
    }
}

複合キーを使用するUse composite keys

前のセクションでは、モデルで使用されるキーの種類の変更について説明し Identity ます。The preceding sections demonstrated changing the type of key used in the Identity model. Identity複合キーを使用するようにキーモデルを変更することはサポートされていないか、推奨されません。Changing the Identity key model to use composite keys isn't supported or recommended. で複合キーを使用する場合は、 Identity マネージャーコードがモデルとどのように連携するかを変更する必要が Identity あります。Using a composite key with Identity involves changing how the Identity manager code interacts with the model. このカスタマイズについては、このドキュメントでは説明しません。This customization is beyond the scope of this document.

テーブル/列の名前とファセットの変更Change table/column names and facets

テーブルと列の名前を変更するには、を呼び出し base.OnModelCreating ます。To change the names of tables and columns, call base.OnModelCreating. 次に、構成を追加して、既定値を上書きします。Then, add configuration to override any of the defaults. たとえば、すべてのテーブルの名前を変更するには、次のようにし Identity ます。For example, to change the name of all the Identity tables:

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    base.OnModelCreating(modelBuilder);

    modelBuilder.Entity<IdentityUser>(b =>
    {
        b.ToTable("MyUsers");
    });

    modelBuilder.Entity<IdentityUserClaim<string>>(b =>
    {
        b.ToTable("MyUserClaims");
    });

    modelBuilder.Entity<IdentityUserLogin<string>>(b =>
    {
        b.ToTable("MyUserLogins");
    });

    modelBuilder.Entity<IdentityUserToken<string>>(b =>
    {
        b.ToTable("MyUserTokens");
    });

    modelBuilder.Entity<IdentityRole>(b =>
    {
        b.ToTable("MyRoles");
    });

    modelBuilder.Entity<IdentityRoleClaim<string>>(b =>
    {
        b.ToTable("MyRoleClaims");
    });

    modelBuilder.Entity<IdentityUserRole<string>>(b =>
    {
        b.ToTable("MyUserRoles");
    });
}

これらの例では、既定の型を使用し Identity ます。These examples use the default Identity types. などのアプリの種類を使用する場合は ApplicationUser 、既定の型ではなく、その型を構成します。If using an app type such as ApplicationUser, configure that type instead of the default type.

次の例では、いくつかの列名を変更します。The following example changes some column names:

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    base.OnModelCreating(modelBuilder);

    modelBuilder.Entity<IdentityUser>(b =>
    {
        b.Property(e => e.Email).HasColumnName("EMail");
    });

    modelBuilder.Entity<IdentityUserClaim<string>>(b =>
    {
        b.Property(e => e.ClaimType).HasColumnName("CType");
        b.Property(e => e.ClaimValue).HasColumnName("CValue");
    });
}

一部の種類のデータベース列は、特定の ファセット を使用して構成でき string ます (許容される最大長など)。Some types of database columns can be configured with certain facets (for example, the maximum string length allowed). 次の例では、モデルのいくつかのプロパティの列の最大長を設定し string ます。The following example sets column maximum lengths for several string properties in the model:

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    base.OnModelCreating(modelBuilder);

    modelBuilder.Entity<IdentityUser>(b =>
    {
        b.Property(u => u.UserName).HasMaxLength(128);
        b.Property(u => u.NormalizedUserName).HasMaxLength(128);
        b.Property(u => u.Email).HasMaxLength(128);
        b.Property(u => u.NormalizedEmail).HasMaxLength(128);
    });

    modelBuilder.Entity<IdentityUserToken<string>>(b =>
    {
        b.Property(t => t.LoginProvider).HasMaxLength(128);
        b.Property(t => t.Name).HasMaxLength(128);
    });
}

別のスキーマにマップするMap to a different schema

スキーマは、データベースプロバイダーによって動作が異なります。Schemas can behave differently across database providers. SQL Server の場合、既定では dbo スキーマのすべてのテーブルが作成されます。For SQL Server, the default is to create all tables in the dbo schema. テーブルは、別のスキーマで作成できます。The tables can be created in a different schema. 次に例を示します。For example:

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    base.OnModelCreating(modelBuilder);

    modelBuilder.HasDefaultSchema("notdbo");
}

遅延読み込みLazy loading

このセクションでは、モデルでの遅延読み込みプロキシのサポートを Identity 追加します。In this section, support for lazy-loading proxies in the Identity model is added. 遅延読み込みは、ナビゲーションプロパティが読み込まれていることを確認せずに使用できるため便利です。Lazy-loading is useful since it allows navigation properties to be used without first ensuring they're loaded.

エンティティ型は、 EF Core のドキュメントで説明されているように、いくつかの方法で遅延読み込みに適したものにすることができます。Entity types can be made suitable for lazy-loading in several ways, as described in the EF Core documentation. わかりやすくするために、レイジー読み込みプロキシを使用します。これには次のものが必要です。For simplicity, use lazy-loading proxies, which requires:

でを呼び出す例を次に示し UseLazyLoadingProxies Startup.ConfigureServices ます。The following example demonstrates calling UseLazyLoadingProxies in Startup.ConfigureServices:

services
    .AddDbContext<ApplicationDbContext>(
        b => b.UseSqlServer(connectionString)
              .UseLazyLoadingProxies())
    .AddDefaultIdentity<ApplicationUser>()
    .AddEntityFrameworkStores<ApplicationDbContext>();

エンティティ型へのナビゲーションプロパティの追加に関するガイダンスについては、前の例を参照してください。Refer to the preceding examples for guidance on adding navigation properties to the entity types.

その他のリソースAdditional resources