У меня есть приложение ASP.NET Core 2.1.0 с использованием EF Core 2.1.0.
Как мне начать посев базы данных с помощью пользователя Admin и дать ему/ей роль администратора? Я не могу найти документацию по этому вопросу.
У меня есть приложение ASP.NET Core 2.1.0 с использованием EF Core 2.1.0.
Как мне начать посев базы данных с помощью пользователя Admin и дать ему/ей роль администратора? Я не могу найти документацию по этому вопросу.
Так как пользователь не может быть отображен в 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);
На самом деле сущность 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
});
}
Вот как я это сделал в итоге. Я создал класс 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;
}
}
Мой 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();
}
Если вы ссылаетесь на пользователей 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 });
Хотелось бы, чтобы там был какой-то лучший/чистый способ сделать это.