如何在EF Core 2.1.0中为Admin用户设定种子?

J86*_*J86 32 c# asp.net-core asp.net-core-2.1 ef-core-2.1

我有一个使用EF Core 2.1.0的ASP.NET Core 2.1.0应用程序.

如何使用Admin用户为数据库播种并为其授予管理员角色?我找不到任何关于此的文件.

Zub*_*ana 44

因为用户无法以正常方式在Identity中播种.HasData(),就像使用.NET Core 2.1 播种其他表一样.

.NET Core 2.1中的种子角色使用以下ApplicationDbContext类中给出的代码:

protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        base.OnModelCreating(modelBuilder);
        // Customize the ASP.NET Identity model and override the defaults if needed.
        // For example, you can rename the ASP.NET Identity table names and more.
        // Add your customizations after calling base.OnModelCreating(builder);

        modelBuilder.Entity<IdentityRole>().HasData(new IdentityRole { Name = "Admin", NormalizedName = "Admin".ToUpper() });
    }
Run Code Online (Sandbox Code Playgroud)

具有角色种子用户按照以下步骤操作.

第1步:创建新类

public static class ApplicationDbInitializer
{
    public static void SeedUsers(UserManager<IdentityUser> userManager)
    {
        if (userManager.FindByEmailAsync("abc@xyz.com").Result==null)
        {
            IdentityUser user = new IdentityUser
            {
                UserName = "abc@xyz.com",
                Email = "abc@xyz.com"
            };

            IdentityResult result = userManager.CreateAsync(user, "PasswordHere").Result;

            if (result.Succeeded)
            {
                userManager.AddToRoleAsync(user, "Admin").Wait();
            }
        }       
    }   
}
Run Code Online (Sandbox Code Playgroud)

第2步:现在修改类中的ConfigureServices方法Startup.cs.

修改前:

services.AddDefaultIdentity<IdentityUser>()
            .AddEntityFrameworkStores<ApplicationDbContext>();
Run Code Online (Sandbox Code Playgroud)

修改后:

services.AddDefaultIdentity<IdentityUser>().AddRoles<IdentityRole>()
            .AddEntityFrameworkStores<ApplicationDbContext>();
Run Code Online (Sandbox Code Playgroud)

第3步:修改类中ConfigureMethod的参数Startup.cs.

修改前:

    public void Configure(IApplicationBuilder app, IHostingEnvironment env)
    {
        //..........
    }
Run Code Online (Sandbox Code Playgroud)

修改后:

public void Configure(IApplicationBuilder app, IHostingEnvironment env, UserManager<IdentityUser> userManager)
    {
        //..........
    }
Run Code Online (Sandbox Code Playgroud)

第4步:调用Seed(ApplicationDbInitializer)类的方法:

ApplicationDbInitializer.SeedUsers(userManager);
Run Code Online (Sandbox Code Playgroud)

  • 应该注意的是,如果使用数据库迁移方法,ApplicationDbInitializer.SeedUsers()发生在modelBuilder.Entity <IdentityRole>().HasData()之后. (4认同)

ten*_*its 29

实际上User可以在一个实体中播种OnModelCreating,有一点需要考虑:IDs应该是预定义的.如果type string用于TKey标识实体,则根本没有问题.

protected override void OnModelCreating(ModelBuilder builder)
{
    base.OnModelCreating(builder);
    // any guid
    const string ADMIN_ID = "a18be9c0-aa65-4af8-bd17-00bd9344e575";
    // any guid, but nothing is against to use the same one
    const string ROLE_ID = ADMIN_ID;
    builder.Entity<IdentityRole>().HasData(new IdentityRole
    {
        Id = ROLE_ID,
        Name = "admin",
        NormalizedName = "admin"
    });

    var hasher = new PasswordHasher<UserEntity>();
    builder.Entity<UserEntity>().HasData(new UserEntity
    {
        Id = ADMIN_ID,
        UserName = "admin",
        NormalizedUserName = "admin",
        Email = "some-admin-email@nonce.fake",
        NormalizedEmail = "some-admin-email@nonce.fake",
        EmailConfirmed = true,
        PasswordHash = hasher.HashPassword(null, "SOME_ADMIN_PLAIN_PASSWORD"),
        SecurityStamp = string.Empty
    });

    builder.Entity<IdentityUserRole<string>>().HasData(new IdentityUserRole<string>
    {
        RoleId = ROLE_ID,
        UserId = ADMIN_ID
    });
}
Run Code Online (Sandbox Code Playgroud)

  • @Marie,“ HasData”方法通过“主键”确保实体存在,因此,当未设置ID时,每次执行seed方法时,都会创建新实体。 (5认同)
  • 为什么要预定义ID? (3认同)
  • 完美运作。如果有人需要引用,则PasswordHasher是NuGet包“ Microsoft.Extensions.Identity.Core”的一部分。 (3认同)
  • 除在每次新迁移中都会生成代码以更新密码哈希值(因为每次运行它都会有所不同)外,它的工作原理都是完美的。 (2认同)

HMZ*_*HMZ 23

ASP.NET 核心 3.1

这就是我如何使用EntityTypeBuilder

角色配置:

public class RoleConfiguration : IEntityTypeConfiguration<IdentityRole>
{
    private const string adminId = "2301D884-221A-4E7D-B509-0113DCC043E1";
    private const string employeeId = "7D9B7113-A8F8-4035-99A7-A20DD400F6A3";
    private const string sellerId = "78A7570F-3CE5-48BA-9461-80283ED1D94D";
    private const string customerId = "01B168FE-810B-432D-9010-233BA0B380E9";

    public void Configure(EntityTypeBuilder<IdentityRole> builder)
    {

        builder.HasData(
                new IdentityRole
                {
                    Id = adminId,
                    Name = "Administrator",
                    NormalizedName = "ADMINISTRATOR"
                },
                new IdentityRole
                {
                    Id = employeeId,
                    Name = "Employee",
                    NormalizedName = "EMPLOYEE"
                },
                new IdentityRole
                {
                    Id = sellerId,
                    Name = "Seller",
                    NormalizedName = "SELLER"
                },
                new IdentityRole
                {
                    Id = customerId,
                    Name = "Customer",
                    NormalizedName = "CUSTOMER"
                }
            );
    }
}
Run Code Online (Sandbox Code Playgroud)

用户配置:

public class AdminConfiguration : IEntityTypeConfiguration<ApplicationUser>
{
    private const string adminId = "B22698B8-42A2-4115-9631-1C2D1E2AC5F7";

    public void Configure(EntityTypeBuilder<ApplicationUser> builder)
    {
        var admin = new ApplicationUser
        {
            Id = adminId,
            UserName = "masteradmin",
            NormalizedUserName = "MASTERADMIN",
            FirstName = "Master",
            LastName = "Admin",
            Email = "Admin@Admin.com",
            NormalizedEmail = "ADMIN@ADMIN.COM",
            PhoneNumber = "XXXXXXXXXXXXX",
            EmailConfirmed = true,
            PhoneNumberConfirmed = true,
            BirthDate = new DateTime(1980,1,1),
            SecurityStamp = new Guid().ToString("D"),
            UserType = UserType.Administrator                
        };

        admin.PasswordHash = PassGenerate(admin);

        builder.HasData(admin);
    }

    public string PassGenerate(ApplicationUser user)
    {
        var passHash = new PasswordHasher<ApplicationUser>();
        return passHash.HashPassword(user, "password");
    }
}
Run Code Online (Sandbox Code Playgroud)

为用户分配角色:

 public class UsersWithRolesConfig : IEntityTypeConfiguration<IdentityUserRole<string>>
    {
        private const string adminUserId = "B22698B8-42A2-4115-9631-1C2D1E2AC5F7";
        private const string adminRoleId = "2301D884-221A-4E7D-B509-0113DCC043E1";

        public void Configure(EntityTypeBuilder<IdentityUserRole<string>> builder)
        {
            IdentityUserRole<string> iur = new IdentityUserRole<string>
            {
                RoleId = adminRoleId,
                UserId = adminUserId
            };

            builder.HasData(iur);
        }
    }
Run Code Online (Sandbox Code Playgroud)

最后在 DB Context 类中:

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

    //If you have alot of data configurations you can use this (works from ASP.Net core 2.2):

    //This will pick up all configurations that are defined in the assembly
    modelBuilder.ApplyConfigurationsFromAssembly(Assembly.GetExecutingAssembly());

    //Instead of this:
    modelBuilder.ApplyConfiguration(new RoleConfiguration());
    modelBuilder.ApplyConfiguration(new AdminConfiguration());
    modelBuilder.ApplyConfiguration(new UsersWithRolesConfig());
}
Run Code Online (Sandbox Code Playgroud)

  • @YegorAndrosov如果您想避免迁移部分,请将逻辑移出“OnModelCreating”并使用“UserManager”和“RoleManager”而不是插入原始值。我仍然认为这种方式更干净,并且更适合播种其他类型的数据。 (2认同)

J86*_*J86 6

这是我最终如何做到的。我创建了一个DbInitializer.cs类来对我的所有数据(包括管理员用户)进行播种。

截屏

以下是与用户帐户播种相关的方法的代码:

private static async Task CreateRole(RoleManager<IdentityRole> roleManager, 
ILogger<DbInitializer> logger, string role)
{
  logger.LogInformation($"Create the role `{role}` for application");
  IdentityResult result = await roleManager.CreateAsync(new IdentityRole(role));
  if (result.Succeeded)
  {
    logger.LogDebug($"Created the role `{role}` successfully");
  }
  else
  {
    ApplicationException exception = new ApplicationException($"Default role `{role}` cannot be created");
    logger.LogError(exception, GetIdentiryErrorsInCommaSeperatedList(result));
    throw exception;
  }
}

private static async Task<ApplicationUser> CreateDefaultUser(UserManager<ApplicationUser> userManager, ILogger<DbInitializer> logger, string displayName, string email)
{
  logger.LogInformation($"Create default user with email `{email}` for application");

  ApplicationUser user = new ApplicationUser
  {
    DisplayUsername = displayName,
    Email = email,
    UserName = email
  };

  IdentityResult identityResult = await userManager.CreateAsync(user);

  if (identityResult.Succeeded)
  {
    logger.LogDebug($"Created default user `{email}` successfully");
  }
  else
  {
    ApplicationException exception = new ApplicationException($"Default user `{email}` cannot be created");
    logger.LogError(exception, GetIdentiryErrorsInCommaSeperatedList(identityResult));
    throw exception;
  }

  ApplicationUser createdUser = await userManager.FindByEmailAsync(email);
  return createdUser;
}

private static async Task SetPasswordForUser(UserManager<ApplicationUser> userManager, ILogger<DbInitializer> logger, string email, ApplicationUser user, string password)
{
  logger.LogInformation($"Set password for default user `{email}`");
  IdentityResult identityResult = await userManager.AddPasswordAsync(user, password);
  if (identityResult.Succeeded)
  {
    logger.LogTrace($"Set password `{password}` for default user `{email}` successfully");
  }
  else
  {
    ApplicationException exception = new ApplicationException($"Password for the user `{email}` cannot be set");
    logger.LogError(exception, GetIdentiryErrorsInCommaSeperatedList(identityResult));
    throw exception;
  }
}
Run Code Online (Sandbox Code Playgroud)

我的Program.cs看起来像这样:

public class Program
{
  public static async Task Main(string[] args)
  {
    var host = BuildWebHost(args);

    using (var scope = host.Services.CreateScope())
    {
      var services = scope.ServiceProvider;
      Console.WriteLine(services.GetService<IConfiguration>().GetConnectionString("DefaultConnection"));
      try
      {
        var context = services.GetRequiredService<PdContext>();
        var userManager = services.GetRequiredService<UserManager<ApplicationUser>>();
        var roleManager = services.GetRequiredService<RoleManager<IdentityRole>>();

        var dbInitializerLogger = services.GetRequiredService<ILogger<DbInitializer>>();
        await DbInitializer.Initialize(context, userManager, roleManager, dbInitializerLogger);
      }
      catch (Exception ex)
      {
        var logger = services.GetRequiredService<ILogger<Program>>();
        logger.LogError(ex, "An error occurred while migrating the database.");
      }
    }

    host.Run();
  }

  public static IWebHost BuildWebHost(string[] args) =>
    WebHost.CreateDefaultBuilder(args)
    .UseStartup<Startup>()
    .Build();
}
Run Code Online (Sandbox Code Playgroud)