IdentityASP.NET Core model özelleştirmesi

Arthur Vicranlar tarafından

ASP.NET Core IdentityASP.NET Core uygulamalarda kullanıcı hesaplarını yönetmek ve depolamak için bir çerçeve sağlar. Identity , kimlik doğrulama mekanizması olarak bireysel kullanıcı hesapları seçildiğinde projenize eklenir. Varsayılan olarak, Identity Entity Framework (EF) temel veri modelini kullanır. Bu makalede, modelin nasıl özelleştirileceği açıklanır Identity .

Identity ve EF Core geçişleri

Modeli incelemeden önce, Identity bir veritabanı oluşturmak ve güncelleştirmek için EF Core geçişlerle nasıl çalıştığını anlamak yararlı olur. En üst düzeyde, işlem şu şekilde yapılır:

  1. Kodda bir veri modelitanımlayın veya güncelleştirin.
  2. Bu modeli veritabanına uygulanabilecek değişikliklere dönüştürmek için bir geçiş ekleyin.
  3. Geçişin, amaclarınızı doğru şekilde temsil ettiğini denetleyin.
  4. Veritabanını modeliyle eşitlenmiş olacak şekilde güncelleştirmek için geçişi uygulayın.
  5. Modeli daha belirginleştirmek ve veritabanını eşitlenmiş halde tutmak için 1 ile 4 arasındaki adımları tekrarlayın.

Geçişleri eklemek ve uygulamak için aşağıdaki yaklaşımlardan birini kullanın:

  • Visual Studio kullanılıyorsa Paket Yöneticisi konsolu (PMC) penceresi. Daha fazla bilgi için bkz. EF Core PMC araçları.
  • Komut satırı kullanılıyorsa .NET Core CLI. Daha fazla bilgi için bkz. .NET komut satırı araçları EF Core.
  • Uygulama çalıştırıldığında hata sayfasındaki geçişleri Uygula düğmesine tıklanın.

ASP.NET Core bir geliştirme zamanı hata sayfası işleyicisine sahiptir. İşleyici, uygulama çalıştırıldığında geçişleri uygulayabilir. üretim uygulamaları tipik olarak geçişlerden SQL betikler oluşturur ve veritabanı değişiklikleri denetimli bir uygulama ve veritabanı dağıtımının bir parçası olarak dağıtılır.

Kullanılarak yeni bir uygulama Identity oluşturulduğunda, yukarıdaki 1. ve 2. adım zaten tamamlanmıştır. Diğer bir deyişle, ilk veri modeli zaten var ve ilk geçiş projeye eklendi. İlk geçişin hala veritabanına uygulanması gerekir. İlk geçiş aşağıdaki yaklaşımlardan biri aracılığıyla uygulanabilir:

  • Update-DatabasePMC 'de çalıştırın.
  • dotnet ef database updateKomut kabuğu 'nda çalıştırın.
  • Uygulama çalıştırıldığında hata sayfasında geçişleri Uygula düğmesine tıklayın.

Modelde değişiklikler yapıldığından önceki adımları yineleyin.

IdentityModel

Varlık türleri

IdentityModel aşağıdaki varlık türlerinden oluşur.

Varlık türü Açıklama
User Kullanıcıyı temsil eder.
Role Bir rolü temsil eder.
UserClaim Bir kullanıcının sahip olduğu talebi temsil eder.
UserToken Bir kullanıcı için kimlik doğrulama belirtecini temsil eder.
UserLogin Kullanıcıyı bir oturum ile ilişkilendirir.
RoleClaim Bir rol içindeki tüm kullanıcılara verilen bir talebi temsil eder.
UserRole Kullanıcıları ve rolleri ilişkilendiren bir JOIN varlığı.

Varlık türü ilişkileri

Varlık türleri , aşağıdaki yollarla birbirleriyle ilişkilidir:

  • Her birinin User çok sayıda olabilir UserClaims .
  • Her birinin User çok sayıda olabilir UserLogins .
  • Her birinin User çok sayıda olabilir UserTokens .
  • Her birinin Role birden çok ilişkili olabilir RoleClaims .
  • Her biri User birden çok ilişkili olabilir Roles ve her biri Role birçok ile ilişkilendirilebilir Users . Bu, veritabanında bir JOIN tablosu gerektiren çoktan çoğa bir ilişkidir. JOIN tablosu varlıkla temsil edilir UserRole .

Varsayılan model yapılandırması

Identitymodeli yapılandırmak ve kullanmak için DbContext 'ten devraldığı birçok bağlam sınıfını tanımlar. bu yapılandırma, bağlam sınıfının onmodeloluþturma yönteminde EF Core Code First Fluent apı 'si kullanılarak yapılır. Varsayılan yapılandırma:

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 genel türleri

Identity Yukarıda listelenen her varlık türü için varsayılan ortak dil çalışma zamanı (CLR) türlerini tanımlar. Bu türlerin öneki Identity :

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

Bu türleri doğrudan kullanmak yerine, türler uygulamanın kendi türleri için temel sınıflar olarak kullanılabilir. DbContextTarafından tanımlanan sınıflar Identity geneldir, örneğin, modeldeki bir veya daha fazla varlık türü IÇIN farklı clr türleri kullanılabilir. Bu genel türler Ayrıca User birincil anahtar (PK) veri türünün değiştirilmesine izin verir.

IdentityRol desteğiyle birlikte kullanıldığında bir IdentityDbContext sınıf kullanılmalıdır. Örnek:

// 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>

Ayrıca Identity , bir IdentityUserContext<TUser> sınıf kullanılması gereken roller (yalnızca talepler) olmadan da kullanılabilir:

// 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>
{
}

Modeli özelleştirme

Model özelleştirmesi için başlangıç noktası uygun bağlam türünden türetilmelidir. Model genel türler bölümüne bakın. bu bağlam türü geleneksel çağırılır ApplicationDbContext ve ASP.NET Core şablonları tarafından oluşturulur.

Bağlam, modeli iki şekilde yapılandırmak için kullanılır:

  • Genel tür parametreleri için varlık ve anahtar türleri sağlama.
  • OnModelCreatingBu türlerin eşlemesini değiştirmek için geçersiz kılma.

Geçersiz kıldığınızda OnModelCreating , base.OnModelCreating ilk olarak çağrılmalıdır; geçersiz kılma yapılandırması daha sonra çağrılmalıdır. EF Core, yapılandırma için genellikle son bir WINS ilkesine sahiptir. Örneğin, bir ToTable varlık türünün yöntemi ilk olarak bir tablo adı ve daha sonra farklı bir tablo adıyla çağrılırsa ikinci çağrıda tablo adı kullanılır.

Özel Kullanıcı verileri

Özel Kullanıcı verileri , öğesinden devralınırken desteklenir IdentityUser . Bu tür için ad vermek önemlidir ApplicationUser :

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

ApplicationUserTürü bağlam için genel bir bağımsız değişken olarak kullanın:

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

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

Sınıfında geçersiz kılınmasına gerek yoktur OnModelCreating ApplicationDbContext . EF Core, CustomTag özelliği kuralına göre eşler. Ancak, veritabanının yeni bir sütun oluşturmak için güncelleştirilmesi gerekir CustomTag . Sütunu oluşturmak için bir geçiş ekleyin ve sonra, Identity ve EF Core geçişleriiçinde açıklandığı gibi veritabanını güncelleştirin.

Sayfaları/paylaşılan/_LoginPartial. cshtml 'yi güncelleştirin ve IdentityUser ile değiştirin ApplicationUser :

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

Alanlarý/ Identity / Identity hostingstartup. cs veya Startup.ConfigureServices IdentityUser ile değiştirin ApplicationUser .

services.AddDefaultIdentity<ApplicationUser>(options => options.SignIn.RequireConfirmedAccount = true)
        .AddEntityFrameworkStores<ApplicationDbContext>();                                    

Çağırma AddDefaultIdentity aşağıdaki koda eşdeğerdir:

services.AddAuthentication(o =>
{
    o.DefaultScheme = IdentityConstants.ApplicationScheme;
    o.DefaultSignInScheme = IdentityConstants.ExternalScheme;
})
.AddIdentityCookies(o => { });

services.AddIdentityCore<TUser>(o =>
{
    o.Stores.MaxLengthForKeys = 128;
    o.SignIn.RequireConfirmedAccount = true;
})
.AddDefaultUI()
.AddDefaultTokenProviders();

Identity bir Razor sınıf kitaplığı olarak sağlanır. Daha fazla bilgi için bkz. ASP.NET Core projelerinde yapı iskelesi Identity. Sonuç olarak, yukarıdaki kod için bir çağrısı gerektirir AddDefaultUI . IdentityProjeye dosya eklemek için desteği kullanılmışsa Identity , çağrısını kaldırın AddDefaultUI . Daha fazla bilgi için bkz.

Birincil anahtar türünü değiştirme

Veritabanı oluşturulduktan sonra PK sütununun veri türünün bir değişikliği birçok veritabanı sisteminde sorunlu olur. PK 'nin değiştirilmesi genellikle tabloyu bırakmayı ve yeniden oluşturmayı içerir. Bu nedenle, veritabanı oluşturulduğunda ilk geçişte anahtar türleri belirtilmelidir.

PK türünü değiştirmek için şu adımları izleyin:

  1. Veritabanı PK değişikliğinden önce oluşturulduysa, Drop-Database dosyayı silmek için (PMC) veya dotnet ef database drop (.NET Core CLI) çalıştırın.

  2. Veritabanını silme işlemini onayladıktan sonra, Remove-Migration (PMC) veya dotnet ef migrations remove (.NET Core CLI) ile ilk geçişi kaldırın.

  3. ApplicationDbContextTüreten türetilmiş sınıfı güncelleştirin IdentityDbContext<TUser,TRole,TKey> . İçin yeni anahtar türünü belirtin TKey . Örneğin, bir Guid anahtar türü kullanmak için:

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

    Önceki kodda, genel sınıflar IdentityUser<TKey> ve IdentityRole<TKey> Yeni anahtar türünü kullanmak için belirtilmelidir.

    Startup.ConfigureServices Genel kullanıcıyı kullanacak şekilde güncelleştirilmeleri gerekir:

    services.AddDefaultIdentity<IdentityUser<Guid>>(options => options.SignIn.RequireConfirmedAccount = true)
            .AddEntityFrameworkStores<ApplicationDbContext>();
    
  4. Özel bir ApplicationUser sınıf kullanılıyorsa, öğesinden devralacak olan sınıfı güncelleştirin IdentityUser . Örnek:

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

    ApplicationDbContextÖzel sınıfa başvurmak için Güncelleştir ApplicationUser :

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

    Hizmeti eklerken özel veritabanı bağlam sınıfını Kaydet Identity Startup.ConfigureServices :

    services.AddDefaultIdentity<ApplicationUser>(options => options.SignIn.RequireConfirmedAccount = true)
            .AddEntityFrameworkStores<ApplicationDbContext>();
    

    Birincil anahtarın veri türü, DbContext nesnesi analiz edilirken algılanır.

    Identity bir Razor sınıf kitaplığı olarak sağlanır. Daha fazla bilgi için bkz. ASP.NET Core projelerinde yapı iskelesi Identity. Sonuç olarak, yukarıdaki kod için bir çağrısı gerektirir AddDefaultUI . IdentityProjeye dosya eklemek için desteği kullanılmışsa Identity , çağrısını kaldırın AddDefaultUI .

  5. Özel bir ApplicationRole sınıf kullanılıyorsa, öğesinden devralacak olan sınıfı güncelleştirin IdentityRole<TKey> . Örnek:

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

    ApplicationDbContextÖzel sınıfa başvurmak için güncelleştirin ApplicationRole . Örneğin, aşağıdaki sınıf özel ve özel bir öğesine başvurur ApplicationUser 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)
        {
        }
    }
    

    Hizmeti eklerken özel veritabanı bağlam sınıfını Kaydet Identity 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);
    }
    

    Birincil anahtarın veri türü, DbContext nesnesi analiz edilirken algılanır.

    Identity bir Razor sınıf kitaplığı olarak sağlanır. Daha fazla bilgi için bkz. ASP.NET Core projelerinde yapı iskelesi Identity. Sonuç olarak, yukarıdaki kod için bir çağrısı gerektirir AddDefaultUI . IdentityProjeye dosya eklemek için desteği kullanılmışsa Identity , çağrısını kaldırın AddDefaultUI .

Gezinti özellikleri ekle

İlişkiler için model yapılandırmasının değiştirilmesi, başka değişiklikler yapmaktan daha zor olabilir. Yeni, ek ilişkiler oluşturmak yerine var olan ilişkilerin yerini almak için dikkatli olunmalıdır. Özellikle, değiştirilen ilişki var olan ilişki olarak aynı yabancı anahtar (FK) özelliğini belirtmelidir. Örneğin, ve arasındaki ilişki Users UserClaims Varsayılan olarak, aşağıdaki şekilde belirtilir:

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

Bu ilişki için FK özellik olarak belirtilir UserClaim.UserId . HasMany ve, ' ın WithOne Gezinti özellikleri olmadan ilişki oluşturmak için bağımsız değişken olmadan çağırılır.

ApplicationUserKullanıcıdan ilişkili olmasına izin veren bir gezinti özelliği ekleyin UserClaims :

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

TKeyİçin, IdentityUserClaim<TKey> Kullanıcı PK için belirtilen türdür. Bu durumda, TKey Varsayılan olarak string kullanılıyor. Varlık türü için PK türü değildir UserClaim .

Artık gezinti özelliği var olduğuna göre, bu, ' de yapılandırılması gerekir 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();
        });
    }
}

İlişkinin yalnızca ' de olduğu gibi, yalnızca çağrısında belirtilen bir gezinti özelliği ile yapılandırıldığından emin olun HasMany .

Gezinti özellikleri, veritabanında değil yalnızca EF modelinde bulunur. İlişki için FK değişmediğinden, bu tür bir model değişikliği veritabanının güncelleştirilmesini gerektirmez. Bu, değişiklik yapıldıktan sonra bir geçiş eklenerek denetlenebilir. UpVe Down yöntemleri boş.

Tüm kullanıcı gezinti özelliklerini Ekle

Aşağıdaki örnek, kılavuz olarak yukarıdaki bölümü kullanarak, Kullanıcı üzerindeki tüm ilişkiler için tek yönlü gezinti özelliklerini yapılandırır:

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();
        });
    }
}

Kullanıcı ve rol gezinti özellikleri ekleme

Aşağıdaki örnek, kılavuz olarak yukarıdaki bölümü kullanarak, Kullanıcı ve roldeki tüm ilişkiler için gezinti özelliklerini yapılandırır:

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();
        });

    }
}

Notlar:

  • Bu örnek ayrıca UserRole , kullanıcılardan rollere kadar çoktan çoğa ilişkiye gitmek için gereken JOIN varlığını içerir.
  • Gezinti özelliklerinin türlerini, türlerin türler yerine kullanılmakta olduğunu yansıtacak şekilde değiştirmeyi unutmayın Application{...} Identity{...} .
  • Öğesini Application{...} genel tanımda kullanmayı unutmayın ApplicationContext .

Tüm gezinti özelliklerini Ekle

Aşağıdaki örnek, kılavuz olarak yukarıdaki bölümü kullanarak tüm varlık türlerindeki tüm ilişkiler için gezinti özelliklerini yapılandırır:

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();
        });
    }
}

Bileşik anahtarlar kullanın

Önceki bölümlerde, modelde kullanılan anahtarın türünü değiştirme gösterilmiştir Identity . IdentityAnahtar modelinin bileşik anahtarları kullanacak şekilde değiştirilmesi desteklenmez veya önerilmez. İle bileşik anahtar kullanılması Identity , Identity yönetici kodunun modelle nasıl etkileşime gireceğini içerir. Bu özelleştirme, bu belgenin kapsamı dışındadır.

Tablo/sütun adlarını ve modelleri değiştirme

Tablo ve sütun adlarını değiştirmek için çağrısı yapın base.OnModelCreating . Ardından, varsayılan ayarları geçersiz kılmak için yapılandırma ekleyin. Örneğin, tüm tabloların adını değiştirmek için Identity :

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");
    });
}

Bu örnekler varsayılan türleri kullanır Identity . Gibi bir uygulama türü kullanıyorsanız ApplicationUser , varsayılan tür yerine bu türü yapılandırın.

Aşağıdaki örnek bazı sütun adlarını değiştirir:

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");
    });
}

Bazı veritabanı sütunları bazı tür bazı modellerle yapılandırılabilir (örneğin, string izin verilen en fazla uzunluk). Aşağıdaki örnek, modeldeki çeşitli özellikler için en fazla sütun uzunluğunu ayarlar string :

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);
    });
}

Farklı bir şemaya eşleme

Şemalar, veritabanı sağlayıcıları genelinde farklı davranabilir. SQL Server için varsayılan, dbo şemasında tüm tabloları oluşturmaktır. Tablolar farklı bir şemada oluşturulabilir. Örnek:

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

    modelBuilder.HasDefaultSchema("notdbo");
}

Geç yükleme

Bu bölümde, modeldeki yavaş yükleme proxy 'leri için destek Identity eklenmiştir. Yavaş yükleme, gezinti özelliklerinin önce yüklendiklerinden emin olmadan kullanılmasına izin verdiğinden yararlıdır.

Varlık türleri, EF Core belgelerindeaçıklandığı gibi çeşitli yollarla yavaş yükleme için uygun hale getirilebilir. Basitlik için, aşağıdakileri gerektiren yavaş yükleme proxy 'leri kullanın:

Aşağıdaki örnekte çağırma gösterilmektedir UseLazyLoadingProxies Startup.ConfigureServices :

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

Varlık türlerine gezinti özellikleri ekleme hakkında rehberlik için yukarıdaki örneklere bakın.

Ek kaynaklar