Как посеять пользователя Admin в EF Core 2.1.0?

У меня есть приложение ASP.NET Core 2.1.0 с использованием EF Core 2.1.0.

Как мне начать посев базы данных с помощью пользователя Admin и дать ему/ей роль администратора? Я не могу найти документацию по этому вопросу.

Ответ 1

Так как пользователь не может быть отображен в 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() });
    }

Семя пользователей с ролями, выполнив следующие действия.

Шаг 1: Создание нового класса

public static class ApplicationDbInitializer
{
    public static void SeedUsers(UserManager<IdentityUser> userManager)
    {
        if (userManager.FindByEmailAsync("[email protected]").Result==null)
        {
            IdentityUser user = new IdentityUser
            {
                UserName = "[email protected]",
                Email = "[email protected]"
            };

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

            if (result.Succeeded)
            {
                userManager.AddToRoleAsync(user, "Admin").Wait();
            }
        }       
    }   
}

Шаг 2: Теперь измените метод ConfigureServices в классе Startup.cs.

До модификации:

services.AddDefaultIdentity<IdentityUser>()
            .AddEntityFrameworkStores<ApplicationDbContext>();

После модификации:

services.AddDefaultIdentity<IdentityUser>().AddRoles<IdentityRole>()
            .AddEntityFrameworkStores<ApplicationDbContext>();

Шаг 3: Измените параметры метода Configure в классе Startup.cs.

До модификации:

    public void Configure(IApplicationBuilder app, IHostingEnvironment env)
    {
        //..........
    }

После внесения изменений:

public void Configure(IApplicationBuilder app, IHostingEnvironment env, UserManager<IdentityUser> userManager)
    {
        //..........
    }

Шаг 4: вызов метода нашего класса Seed (ApplicationDbInitializer):

ApplicationDbInitializer.SeedUsers(userManager);

Ответ 2

На самом деле сущность User может быть добавлена в OnModelCreating, но следует учитывать одну вещь: ID должен быть предопределен. Если для идентификаторов TKey используется тип string, то проблем нет вообще.

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 = "[email protected]",
        NormalizedEmail = "[email protected]",
        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
    });
}

Ответ 3

Вот как я это сделал в итоге. Я создал класс DbInitializer.cs для заполнения всех моих данных (включая администратора).

screenshot

Вот код для методов, относящихся к заполнению учетных записей пользователей:

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

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

Ответ 4

Если вы ссылаетесь на пользователей Identity, то, как мы это делали, это добавлять жестко заданные значения в DbContext.OnModelCreating:

builder.Entity<Role>().HasData(new Role { Id = 2147483645, Name = UserRole.Admin.ToString(), NormalizedName = UserRole.Admin.ToString().ToUpper(), ConcurrencyStamp = "123c90a4-dfcb-4e77-91e9-d390b5b6e21b" });

И пользователь:

builder.Entity<User>().HasData(new User
        {
            Id = 2147483646,
            AccessFailedCount = 0,
            PasswordHash = "SomePasswordHashKnownToYou",
            LockoutEnabled = true,
            FirstName = "AdminFName",
            LastName = "AdminLName",
            UserName = "admin",
            Email = "[email protected]",
            EmailConfirmed = true,
            InitialPaymentCompleted = true,
            MaxUnbalancedTech = 1,
            UniqueStamp = "2a1a39ef-ccc0-459d-aa9a-eec077bfdd22",
            NormalizedEmail = "[email protected]",
            NormalizedUserName = "ADMIN",
            TermsOfServiceAccepted = true,
            TermsOfServiceAcceptedTimestamp = new DateTime(2018, 3, 24, 7, 42, 35, 10, DateTimeKind.Utc),
            SecurityStamp = "ce907fd5-ccb4-4e96-a7ea-45712a14f5ef",
            ConcurrencyStamp = "32fe9448-0c6c-43b2-b605-802c19c333a6",
            CreatedTime = new DateTime(2018, 3, 24, 7, 42, 35, 10, DateTimeKind.Utc),
            LastModified = new DateTime(2018, 3, 24, 7, 42, 35, 10, DateTimeKind.Utc)
        });

builder.Entity<UserRoles>().HasData(new UserRoles() { RoleId = 2147483645, UserId = 2147483646 });

Хотелось бы, чтобы там был какой-то лучший/чистый способ сделать это.