اضافه کردن نقش پیشفرض Admin
اولین تغییری که در اینجا مورد نیاز است، افزودن نقش پیشفرض Admin است. برای این منظور توسط یک IEntityTypeConfiguration جدید، تنظیمات موجودیت سفارشی Role برنامه را به نحو زیر انجام میدهیم:
namespace ASPNETCoreIdentitySample.DataLayer.Mappings { public class RoleConfiguration : IEntityTypeConfiguration<Role> { private readonly SiteSettings _siteSettings; private readonly ILookupNormalizer _keyNormalizer; public RoleConfiguration(SiteSettings siteSettings, ILookupNormalizer keyNormalizer) { _siteSettings = siteSettings ?? throw new ArgumentNullException(nameof(siteSettings)); _keyNormalizer = keyNormalizer ?? throw new ArgumentNullException(nameof(keyNormalizer)); } public void Configure(EntityTypeBuilder<Role> builder) { builder.ToTable("AppRoles"); var adminUserSeed = _siteSettings.AdminUserSeed; builder.HasData( new Role { Id = 1, Name = adminUserSeed.RoleName, NormalizedName = _keyNormalizer.NormalizeName(adminUserSeed.RoleName), ConcurrencyStamp = Guid.NewGuid().ToString() }); } } }
الف) NormalizedName از طریق سرویس ILookupNormalizer در ASP.NET Core Identity تامین میشود.
ب) SiteSettings در اینجا جهت دریافت نام نقش Admin از فایل appsettings.json، تعریف شدهاست (تامین مقدار پیشفرض).
اضافه کردن کاربر پیشفرض Admin
برای اضافه کردن کاربر پیشفرض ادمین، علاوه بر سرویس ILookupNormalizer که کار تامین مقادیر NormalizedEmail و NormalizedUserName را به عهده دارد، نیاز به سرویس IPasswordHasher نیز میباشد. از آن برای تامین مقدار فیلد PasswordHash، بر اساس سرویس هش کردن پسوردهای توکار ASP.NET Core Identity، استفاده میکنیم. برای این منظور توسط یک IEntityTypeConfiguration جدید، تنظیمات موجودیت سفارشی User برنامه را به نحو زیر انجام میدهیم:
public class UserConfiguration : IEntityTypeConfiguration<User> { private readonly SiteSettings _siteSettings; private readonly ILookupNormalizer _keyNormalizer; private readonly IPasswordHasher<User> _passwordHasher; public UserConfiguration( SiteSettings siteSettings, ILookupNormalizer keyNormalizer, IPasswordHasher<User> passwordHasher) { _siteSettings = siteSettings ?? throw new ArgumentNullException(nameof(siteSettings)); _keyNormalizer = keyNormalizer ?? throw new ArgumentNullException(nameof(keyNormalizer)); _passwordHasher = passwordHasher ?? throw new ArgumentNullException(nameof(passwordHasher)); } public void Configure(EntityTypeBuilder<User> builder) { builder.ToTable("AppUsers"); var adminUserSeed = _siteSettings.AdminUserSeed; builder.HasData( new User { Id = 1, UserName = adminUserSeed.Username, NormalizedUserName = _keyNormalizer.NormalizeName(adminUserSeed.Username), Email = adminUserSeed.Email, NormalizedEmail = _keyNormalizer.NormalizeEmail(adminUserSeed.Email), EmailConfirmed = true, IsEmailPublic = true, LockoutEnabled = true, TwoFactorEnabled = false, PasswordHash = _passwordHasher.HashPassword(null, adminUserSeed.Password), ConcurrencyStamp = Guid.NewGuid().ToString(), SecurityStamp = string.Empty, IsActive = true }); } }
انتساب دادن نقش Admin، به کاربر Admin
تا اینجا نقش ادمین و کاربر ادمین را به صورت مجزا ایجاد کردیم. مرحلهی آخر، انتساب این نقش، به کاربر ادمین است که بر اساس Id این دو صورت میگیرد. برای این منظور توسط یک IEntityTypeConfiguration جدید، تنظیمات موجودیت سفارشی UserRole برنامه را به نحو زیر انجام میدهیم:
public class UserRoleConfiguration : IEntityTypeConfiguration<UserRole> { public void Configure(EntityTypeBuilder<UserRole> builder) { builder.HasOne(userRole => userRole.Role) .WithMany(role => role.Users) .HasForeignKey(userRole => userRole.RoleId); builder.HasOne(userRole => userRole.User) .WithMany(user => user.Roles) .HasForeignKey(userRole => userRole.UserId); builder.ToTable("AppUserRoles"); builder.HasData( new UserRole { UserId = 1, RoleId = 1 }); } }
اتصال IEntityTypeConfiguration به DbContext برنامه
IEntityTypeConfigurationهای تهیه شده، دارای سازندههایی هستند که تعدادی سرویس را دریافت میکنند. روش معرفی آنها به این صورت است:
الف) تامین دو سرویس ILookupNormalizer و IPasswordHasher در IDesignTimeDbContextFactory تهیه شده:
public class ApplicationDbContextFactory : IDesignTimeDbContextFactory<ApplicationDbContext> { public ApplicationDbContext CreateDbContext(string[] args) { // .... services.TryAddScoped<ILookupNormalizer, UpperInvariantLookupNormalizer>(); services.TryAddScoped<IPasswordHasher<User>, PasswordHasher<User>>();
ب) پس از تامین این سرویسها، روش معرفی آنها به متدهای modelBuilder.ApplyConfiguration در متد OnModelCreating، توسط متد this.GetService به صورت زیر است. متد this.GetService از فضای نام Microsoft.EntityFrameworkCore.Infrastructure تامین میشود و فقط یکبار در زمان Migration از طریق IDesignTimeDbContextFactory تامین خواهد شد:
using Microsoft.EntityFrameworkCore.Infrastructure; namespace ASPNETCoreIdentitySample.DataLayer.Context { public class ApplicationDbContext : IdentityDbContext<User, Role, int, UserClaim, UserRole, UserLogin, RoleClaim, UserToken>, IUnitOfWork { public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options) : base(options) { } protected override void OnModelCreating(ModelBuilder modelBuilder) { base.OnModelCreating(modelBuilder); var siteSettings = this.GetService<IOptionsSnapshot<SiteSettings>>()?.Value; var lookupNormalizer = this.GetService<ILookupNormalizer>(); var passwordHasher = this.GetService<IPasswordHasher<User>>() modelBuilder.ApplyConfiguration(new RoleConfiguration(siteSettings, lookupNormalizer)); modelBuilder.ApplyConfiguration(new UserConfiguration(siteSettings, lookupNormalizer, passwordHasher)); modelBuilder.ApplyConfiguration(new UserUsedPasswordConfiguration(siteSettings, passwordHasher)); // ...
پس از این تغییرات اگر دستور Migration زیر را صادر کنیم:
dotnet ef migrations --startup-project ../ASPNETCoreIdentitySample/ add V1