我有一个使用 EF Core 2.1.0 的 ASP.NET Core 2.1.0 应用程序。
如何使用管理员用户播种数据库并给他/她一个管理员角色?我找不到任何关于此的文档。
我有一个使用 EF Core 2.1.0 的 ASP.NET Core 2.1.0 应用程序。
如何使用管理员用户播种数据库并给他/她一个管理员角色?我找不到任何关于此的文档。
由于用户无法以正常方式在 Identity 中播种,就像其他表使用.HasData()
.NET Core 2.1 播种一样。
Microsoft 建议:对于需要调用外部 API 的数据,例如 ASP.NET Core Identity 用户创建,建议使用自定义初始化逻辑。
.NET Core 2.1 中的种子角色ApplicationDbContext
使用下面给出的代码Class :
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("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();
}
}
}
}
第2步:现在修改类中ConfigureServices
的方法Startup.cs
。
修改前:
services.AddDefaultIdentity<IdentityUser>()
.AddEntityFrameworkStores<ApplicationDbContext>();
修改后:
services.AddDefaultIdentity<IdentityUser>().AddRoles<IdentityRole>()
.AddEntityFrameworkStores<ApplicationDbContext>();
第三步:修改类中Configure
Method的参数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);
注意:您也可以像RoleManager
用户一样通过注入UserManager
.
实际上User
可以在 Entity 中播种OnModelCreating
,需要考虑的一件事是:ID
s 应该是预定义的。如果 typestring
用于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
});
}
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"
}
);
}
}
用户配置:
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");
}
}
为用户分配角色:
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);
}
}
最后在 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());
}
这就是我最后是如何做到的。我创建了一个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();
}
这是基于.NET 6
个人用户帐户,然后是脚手架身份。用户被创建,然后根据微软的代码收到一封确认的电子邮件。
然后,您可以按照@Zubair Rana 的回答播种角色。
https://stackoverflow.com/a/51571555/3850405
程序.cs:
public class Program
{
public static void Main(string[] args)
{
var host = CreateHostBuilder(args).Build();
CreateDbAndRunMigrations(host);
host.Run();
}
private static void CreateDbAndRunMigrations(IHost host)
{
using (var scope = host.Services.CreateScope())
{
var services = scope.ServiceProvider;
var context = services.GetRequiredService<ApplicationDbContext>();
context.Database.Migrate();
var userStore = services.GetRequiredService<IUserStore<ApplicationUser>>();
var userManager = services.GetRequiredService<UserManager<ApplicationUser>>();
DbInitializer.Initialize(context, userManager, userStore);
}
}
}
DbInitializer.cs:
public static class DbInitializer
{
public static void Initialize(ApplicationDbContext context, UserManager<ApplicationUser> userManager, IUserStore<ApplicationUser> userStore)
{
if (context.Users.Any())
{
return; // DB has been seeded
}
var user = Activator.CreateInstance<ApplicationUser>();
var email = "example@example.com";
var emailStore = (IUserEmailStore<ApplicationUser>)userStore;
//Will not be used - Has to use Forgot Password. Last characters used to make sure password validation passes
var password = GetUniqueKey(40) + "aA1!";
userStore.SetUserNameAsync(user, email, CancellationToken.None).Wait();
emailStore.SetEmailAsync(user, email, CancellationToken.None).Wait();
var result = userManager.CreateAsync(user, password).Result;
if (result.Succeeded)
{
var userId = userManager.GetUserIdAsync(user).Result;
var code = userManager.GenerateEmailConfirmationTokenAsync(user).Result;
userManager.ConfirmEmailAsync(user, code).Wait();
}
else
{
throw new Exception();
}
}
private static string GetUniqueKey(int size)
{
var chars =
"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890!+?*~".ToCharArray();
byte[] data = new byte[4*size];
using (var crypto = RandomNumberGenerator.Create())
{
crypto.GetBytes(data);
}
StringBuilder result = new StringBuilder(size);
for (int i = 0; i < size; i++)
{
var rnd = BitConverter.ToUInt32(data, i * 4);
var idx = rnd % chars.Length;
result.Append(chars[idx]);
}
return result.ToString();
}
}
如果您指的是身份用户,我们所做的方法是在 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 = "admin@gmail.com",
EmailConfirmed = true,
InitialPaymentCompleted = true,
MaxUnbalancedTech = 1,
UniqueStamp = "2a1a39ef-ccc0-459d-aa9a-eec077bfdd22",
NormalizedEmail = "ADMIN@GMAIL.COM",
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 });
我希望有一些更好/更清洁的方法来做到这一点。