如何使用 Identity ASP.NET Core 通过代码优先迁移为用户和角色播种
How to Seed Users and Roles with Code First Migration using Identity ASP.NET Core
我创建了一个干净的新 asp.net 5 项目 (rc1-final)。使用身份验证,我只有 ApplicationDbContext.cs 和以下代码:
public class ApplicationDbContext : IdentityDbContext<ApplicationUser>
{
protected override void OnModelCreating(ModelBuilder builder)
{
// On event model creating
base.OnModelCreating(builder);
}
}
请注意 ApplicationDbContext 使用 IdentityDbContext 而不是 DbContext。
有任何IdentityConfig.cs。如果经典的 protected override void Seed 不存在,我需要在哪里创建角色和用户?
这是not yet implemented。作为解决方法,只需编写您自己的 class 来检查数据库中是否存在您的实体,如果它们不存在则添加它们,然后从您的 Startup.cs 中调用此 class .
我的方法是在模型命名空间中创建一个 class。
public class SampleData
{
public static void Initialize(IServiceProvider serviceProvider)
{
var context = serviceProvider.GetService<ApplicationDbContext>();
string[] roles = new string[] { "Owner", "Administrator", "Manager", "Editor", "Buyer", "Business", "Seller", "Subscriber" };
foreach (string role in roles)
{
var roleStore = new RoleStore<IdentityRole>(context);
if (!context.Roles.Any(r => r.Name == role))
{
roleStore.CreateAsync(new IdentityRole(role));
}
}
var user = new ApplicationUser
{
FirstName = "XXXX",
LastName = "XXXX",
Email = "xxxx@example.com",
NormalizedEmail = "XXXX@EXAMPLE.COM",
UserName = "Owner",
NormalizedUserName = "OWNER",
PhoneNumber = "+111111111111",
EmailConfirmed = true,
PhoneNumberConfirmed = true,
SecurityStamp = Guid.NewGuid().ToString("D")
};
if (!context.Users.Any(u => u.UserName == user.UserName))
{
var password = new PasswordHasher<ApplicationUser>();
var hashed = password.HashPassword(user,"secret");
user.PasswordHash = hashed;
var userStore = new UserStore<ApplicationUser>(context);
var result = userStore.CreateAsync(user);
}
AssignRoles(serviceProvider, user.Email, roles);
context.SaveChangesAsync();
}
public static async Task<IdentityResult> AssignRoles(IServiceProvider services, string email, string[] roles)
{
UserManager<ApplicationUser> _userManager = services.GetService<UserManager<ApplicationUser>>();
ApplicationUser user = await _userManager.FindByEmailAsync(email);
var result = await _userManager.AddToRolesAsync(user, roles);
return result;
}
}
到 运行 启动时的代码。在路由配置之后的配置方法末尾的 Startup.cs 中,按照 Stafford Williams 之前所说的添加以下代码。
SampleData.Initialize(app.ApplicationServices);
以下行在 AspNetRoles table 中创建条目,但不填充 NormalizedName 列。
用以下内容替换要填充的此列:
RoleManager<IdentityRole> roleManager = serviceProvider.GetService<RoleManager<IdentityRole>>();
roleManager.CreateAsync(new IdentityRole(role));
截至撰写本文时,还没有用于植入数据库的插件,但您可以创建一个 class 并将其添加到您的容器中,以便在应用程序启动时执行相同的操作,此处我是这样做的,首先创建一个 class:
public class YourDbContextSeedData
{
private YourDbContext _context;
public YourDbContextSeedData(YourDbContext context)
{
_context = context;
}
public async void SeedAdminUser()
{
var user = new ApplicationUser
{
UserName = "Email@email.com",
NormalizedUserName = "email@email.com",
Email = "Email@email.com",
NormalizedEmail = "email@email.com",
EmailConfirmed = true,
LockoutEnabled = false,
SecurityStamp = Guid.NewGuid().ToString()
};
var roleStore = new RoleStore<IdentityRole>(_context);
if (!_context.Roles.Any(r => r.Name == "admin"))
{
await roleStore.CreateAsync(new IdentityRole { Name = "admin", NormalizedName = "admin" });
}
if (!_context.Users.Any(u => u.UserName == user.UserName))
{
var password = new PasswordHasher<ApplicationUser>();
var hashed = password.HashPassword(user, "password");
user.PasswordHash = hashed;
var userStore = new UserStore<ApplicationUser>(_context);
await userStore.CreateAsync(user);
await userStore.AddToRoleAsync(user, "admin");
}
await _context.SaveChangesAsync();
}
在 Startup.cs
的 ConfigureServices
方法中注册类型 class:
services.AddTransient<YourDbContextSeedData>();
接下来将 YourDbContextSeedData
class 传递给 Startup.cs
class 的 Configure
方法并使用它:
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory, YourDbContextSeedData seeder)
{
seeder.SeedAdminUser();
}
在模型命名空间中添加以下内容 class。它适用于添加多个用户和角色,并且还将为现有用户添加角色(例如 facbook 登录)。从 startup.cs
中这样称呼它 app.SeedUsersAndRoles();
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNet.Builder;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.AspNet.Identity.EntityFramework;
using Microsoft.AspNet.Identity;
namespace MyApplication.Models
{
public static class DataSeeder
{
public static async void SeedUsersAndRoles(this IApplicationBuilder app)
{
var context = app.ApplicationServices.GetService<ApplicationDbContext>();
UserWithRoles[] usersWithRoles = {
new UserWithRoles("Admin", new string[] { "Administrator" , "Distributor" },"somepassword"),//user and optional roles and password you want to seed
new UserWithRoles("PlainUser"),
new UserWithRoles("Jojo",new string[]{"Distributor" }) //seed roles to existing users (e.g. facebook login).
};
foreach (var userWithRoles in usersWithRoles)
{
foreach (string role in userWithRoles.Roles)
if (!context.Roles.Any(r => r.Name == role))
{
var roleStore = new RoleStore<IdentityRole>(context);
await roleStore.CreateAsync(new IdentityRole(role));
}
var ExistingUser = context.Users.FirstOrDefault(p => p.NormalizedUserName == userWithRoles.User.NormalizedUserName);
if (ExistingUser == null) //the following syntax: !context.Users.FirstOrDefault(p => p.NormalizedUserName == userWithRoles.User.NormalizedUserName))
//provokes execption:(ExecuteReader requires an open and available Connection.)
await new UserStore<ApplicationUser>(context).CreateAsync(userWithRoles.User);
await app.AssignRoles(userWithRoles); //assign also to existing users.
}
context.SaveChangesAsync();
}
public static async Task<IdentityResult> AssignRoles(this IApplicationBuilder app, UserWithRoles uWR)
{
UserManager<ApplicationUser> _userManager = app.ApplicationServices.GetService<UserManager<ApplicationUser>>();
ApplicationUser user = await _userManager.FindByNameAsync(uWR.User.NormalizedUserName);
var result = await _userManager.AddToRolesAsync(user, uWR.Roles);
return result;
}
}
public class UserWithRoles
{
private ApplicationUser user;
public ApplicationUser User { get { return user; } }
public string[] Roles { get; set; }
public UserWithRoles(string name, string[] roles = null, string password = "secret")
{
if (roles != null)
Roles = roles;
else
Roles = new string[] { };
user = new ApplicationUser
{
Email = name + "@gmail.com", NormalizedEmail = name.ToUpper() + "@GMAIL.COM",
UserName = name, NormalizedUserName = name.ToUpper(),
PhoneNumber = "+1312341234",
EmailConfirmed = true,
PhoneNumberConfirmed = true,
SecurityStamp = Guid.NewGuid().ToString("D"),
};
user.PasswordHash = new PasswordHasher<ApplicationUser>().HashPassword(user, password);
}
}
}
所以这是基于 Muhammad Abdullah 回答的解决方案。包括一些代码改进、提高代码的可读性并让它与 .net core 2 一起工作。
public class Seed
{
public static async Task Initialize(IServiceProvider serviceProvider, IConfiguration configuration)
{
var usrName = configuration.GetSection("Admin").GetSection("UserName").Value;
var email = configuration.GetSection("Admin").GetSection("Email").Value;
var pass = configuration.GetSection("Admin").GetSection("Pass").Value;
var roles = new string[4] { OWNER, ADMIN, SENIOR, USER };
if(await CreateUser(serviceProvider, email, usrName, pass, roles))
{
await AddToRoles(serviceProvider, email, roles);
}
}
private static async Task<bool> CreateUser(IServiceProvider serviceProvider, string email, string usrName, string pass, string[] roles)
{
var res = false;
using (var scope = serviceProvider.CreateScope())
{
var context = scope.ServiceProvider.GetService<BaseContext>();
if (!context.ApplicationUsers.Any(u => u.NormalizedUserName == usrName.ToUpper()))
{
var roleStore = scope.ServiceProvider.GetService<RoleManager<IdentityRole>>();
foreach (string role in roles)
{
if (!context.Roles.Any(r => r.Name == role))
{
await roleStore.CreateAsync(new IdentityRole(role)).ConfigureAwait(false);
}
}
var user = new ApplicationUser
{
UserName = usrName,
Email = email,
EmailConfirmed = true,
NormalizedEmail = email.ToUpper(),
NormalizedUserName = usrName.ToUpper(),
PhoneNumber = null,
PhoneNumberConfirmed = true,
SecurityStamp = Guid.NewGuid().ToString()
};
var password = new PasswordHasher<ApplicationUser>();
user.PasswordHash = password.HashPassword(user, pass); ;
var userStore = new UserStore<ApplicationUser>(context);
res = (await userStore.CreateAsync(user).ConfigureAwait(false)).Succeeded;
}
return res;
}
}
private static async Task AddToRoles(IServiceProvider serviceProvider, string email, string[] roles)
{
using (var scope = serviceProvider.CreateScope())
{
var userManager = scope.ServiceProvider.GetService<UserManager<ApplicationUser>>();
var usr = await userManager.FindByEmailAsync(email).ConfigureAwait(false);
await userManager.AddToRolesAsync(usr, roles).ConfigureAwait(false);
}
}
}
如果您遇到异步问题,请尝试以下代码:
protected override void Seed(ApplicationDbContext context)
{
// This method will be called after migrating to the latest version.
string[] roles = new string[] { "Admin", "User" };
foreach (string role in roles)
{
if (!context.Roles.Any(r => r.Name == role))
{
context.Roles.Add(new IdentityRole(role));
}
}
//create user UserName:Owner Role:Admin
if (!context.Users.Any(u => u.UserName == "Owner"))
{
var userManager = new UserManager<ApplicationUser>(new UserStore<ApplicationUser>(context));
var user = new ApplicationUser
{
FirstName = "XXXX",
LastName = "XXXX",
Email = "xxxx@example.com",
UserName = "Owner",
PhoneNumber = "+111111111111",
EmailConfirmed = true,
PhoneNumberConfirmed = true,
SecurityStamp = Guid.NewGuid().ToString("D"),
PasswordHash = userManager.PasswordHasher.HashPassword("secret"),
LockoutEnabled = true,
};
userManager.Create(user);
userManager.AddToRole(user.Id, "Admin");
}
context.SaveChanges();
}
似乎这个线程很旧,但它仍然适用于想要在 entityframework 核心中播种身份表数据的人。
您可以简单地尝试以下操作。
modelBuilder.Entity<IdentityUser>().HasData(
new IdentityUser { Id= "-1", UserName="sagark",PasswordHash="sagark", Email="emailid goes here" }
);
您可以在 IdentityDbContext.cs 文件内的 OnModelCreating() 方法中播种用户和角色,如下所示。请注意,必须预定义密钥以避免每次执行此方法时都会播种新用户和角色。
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
//Seeding a 'Administrator' role to AspNetRoles table
modelBuilder.Entity<IdentityRole>().HasData(new IdentityRole {Id = "2c5e174e-3b0e-446f-86af-483d56fd7210", Name = "Administrator", NormalizedName = "ADMINISTRATOR".ToUpper() });
//a hasher to hash the password before seeding the user to the db
var hasher = new PasswordHasher<IdentityUser>();
//Seeding the User to AspNetUsers table
modelBuilder.Entity<IdentityUser>().HasData(
new IdentityUser
{
Id = "8e445865-a24d-4543-a6c6-9443d048cdb9", // primary key
UserName = "myuser",
NormalizedUserName = "MYUSER",
PasswordHash = hasher.HashPassword(null, "Pa$$w0rd")
}
);
//Seeding the relation between our user and role to AspNetUserRoles table
modelBuilder.Entity<IdentityUserRole<string>>().HasData(
new IdentityUserRole<string>
{
RoleId = "2c5e174e-3b0e-446f-86af-483d56fd7210",
UserId = "8e445865-a24d-4543-a6c6-9443d048cdb9"
}
);
}
aspnetcore中有IHostedService的概念。这使得 运行 异步背景成为可能 Task
.
@hamid-mosalla 的解决方案可以 async
并从 IHostedService
实现中调用。
种子 class 实现可能类似于
public class IdentityDataSeeder
{
private readonly UserManager<ApplicationUser> _userManager;
private readonly RoleManager<IdentityRole> _roleManager;
public IdentityDataSeeder(
UserManager<ApplicationUser> userManager,
RoleManager<IdentityRole> roleManager)
{
_userManager = userManager;
_roleManager = roleManager;
}
public async Task SeedAsync()
{
var superAdminRole = new IdentityRole
{
Id = "cac43a6e-f7bb-4448-baaf-1add431ccbbf",
Name = "SuperAdmin",
NormalizedName = "SUPERADMIN"
};
await CreateRoleAsync(superAdminRole);
var superAdminUserPassword = "P@ssword1";
var superAdminUser = new ApplicationUser
{
Id = "b8633e2d-a33b-45e6-8329-1958b3252bbd",
UserName = "admin@example.nl",
NormalizedUserName = "ADMIN@EXAMPLE.NL",
Email = "admin@example.nl",
NormalizedEmail = "ADMIN@EXAMPLE.NL",
EmailConfirmed = true,
};
await CreateUserAsync(superAdminUser, superAdminUserPassword);
var superAdminInRole = await _userManager.IsInRoleAsync(superAdminUser, superAdminRole.Name);
if (!superAdminInRole)
await _userManager.AddToRoleAsync(superAdminUser, superAdminRole.Name);
}
private async Task CreateRoleAsync(IdentityRole role)
{
var exits = await _roleManager.RoleExistsAsync(role.Name);
if (!exits)
await _roleManager.CreateAsync(role);
}
private async Task CreateUserAsync(ApplicationUser user, string password)
{
var exists = await _userManager.FindByEmailAsync(user.Email);
if (exists == null)
await _userManager.CreateAsync(user, password);
}
}
这可以从 IHostedService
:
public class SetupIdentityDataSeeder : IHostedService
{
private readonly IServiceProvider _serviceProvider;
public SetupIdentityDataSeeder(IServiceProvider serviceProvider)
{
_serviceProvider = serviceProvider;
}
public async Task StartAsync(CancellationToken cancellationToken)
{
using (var scope = _serviceProvider.CreateScope())
{
var seeder = scope.ServiceProvider.GetRequiredService<IdentityDataSeeder>();
await seeder.SeedAsync();
}
}
public Task StopAsync(CancellationToken cancellationToken) => Task.CompletedTask;
}
Startup
看起来像:
public void ConfigureServices(IServiceCollection services)
{
//...
services.AddHostedService<SetupIdentityDataSeeder>();
}
我的方式:
在模型文件夹中创建 Class
public static class ModelBuilderExtensions
{
public static void Seed(this ModelBuilder builder)
{
// Seed Roles
List<IdentityRole> roles = new List<IdentityRole>()
{
new IdentityRole { Name = "Admin", NormalizedName = "ADMIN" },
new IdentityRole { Name = "User", NormalizedName = "USER" }
};
builder.Entity<IdentityRole>().HasData(roles);
// -----------------------------------------------------------------------------
// Seed Users
var passwordHasher = new PasswordHasher<ApplicationUser>();
List<ApplicationUser> users = new List<ApplicationUser>()
{
// imporant: don't forget NormalizedUserName, NormalizedEmail
new ApplicationUser {
UserName = "user2@hotmail.com",
NormalizedUserName = "USER2@HOTMAIL.COM",
Email = "user2@hotmail.com",
NormalizedEmail = "USER2@HOTMAIL.COM",
},
new ApplicationUser {
UserName = "user3@hotmail.com",
NormalizedUserName = "USER3@HOTMAIL.COM",
Email = "user3@hotmail.com",
NormalizedEmail = "USER3@HOTMAIL.COM",
},
};
builder.Entity<ApplicationUser>().HasData(users);
///----------------------------------------------------
// Seed UserRoles
List<IdentityUserRole<string>> userRoles = new List<IdentityUserRole<string>>();
// Add Password For All Users
users[0].PasswordHash = passwordHasher.HashPassword(users[0], "User.123");
users[1].PasswordHash = passwordHasher.HashPassword(users[1], "User.155");
userRoles.Add(new IdentityUserRole<string> { UserId = users[0].Id, RoleId =
roles.First(q => q.Name == "User").Id });
userRoles.Add(new IdentityUserRole<string> { UserId = users[1].Id, RoleId =
roles.First(q => q.Name == "Admin").Id });
builder.Entity<IdentityUserRole<string>>().HasData(userRoles);
}}
在 DBContext
public class AppDbContext : IdentityDbContext<ApplicationUser>
{
public AppDbContext(DbContextOptions<AppDbContext> options)
: base(options)
{
}
protected override void OnModelCreating(ModelBuilder builder)
{
// Use seed method here
builder.Seed();
base.OnModelCreating(builder);
}}
我创建了一个干净的新 asp.net 5 项目 (rc1-final)。使用身份验证,我只有 ApplicationDbContext.cs 和以下代码:
public class ApplicationDbContext : IdentityDbContext<ApplicationUser>
{
protected override void OnModelCreating(ModelBuilder builder)
{
// On event model creating
base.OnModelCreating(builder);
}
}
请注意 ApplicationDbContext 使用 IdentityDbContext 而不是 DbContext。
有任何IdentityConfig.cs。如果经典的 protected override void Seed 不存在,我需要在哪里创建角色和用户?
这是not yet implemented。作为解决方法,只需编写您自己的 class 来检查数据库中是否存在您的实体,如果它们不存在则添加它们,然后从您的 Startup.cs 中调用此 class .
我的方法是在模型命名空间中创建一个 class。
public class SampleData
{
public static void Initialize(IServiceProvider serviceProvider)
{
var context = serviceProvider.GetService<ApplicationDbContext>();
string[] roles = new string[] { "Owner", "Administrator", "Manager", "Editor", "Buyer", "Business", "Seller", "Subscriber" };
foreach (string role in roles)
{
var roleStore = new RoleStore<IdentityRole>(context);
if (!context.Roles.Any(r => r.Name == role))
{
roleStore.CreateAsync(new IdentityRole(role));
}
}
var user = new ApplicationUser
{
FirstName = "XXXX",
LastName = "XXXX",
Email = "xxxx@example.com",
NormalizedEmail = "XXXX@EXAMPLE.COM",
UserName = "Owner",
NormalizedUserName = "OWNER",
PhoneNumber = "+111111111111",
EmailConfirmed = true,
PhoneNumberConfirmed = true,
SecurityStamp = Guid.NewGuid().ToString("D")
};
if (!context.Users.Any(u => u.UserName == user.UserName))
{
var password = new PasswordHasher<ApplicationUser>();
var hashed = password.HashPassword(user,"secret");
user.PasswordHash = hashed;
var userStore = new UserStore<ApplicationUser>(context);
var result = userStore.CreateAsync(user);
}
AssignRoles(serviceProvider, user.Email, roles);
context.SaveChangesAsync();
}
public static async Task<IdentityResult> AssignRoles(IServiceProvider services, string email, string[] roles)
{
UserManager<ApplicationUser> _userManager = services.GetService<UserManager<ApplicationUser>>();
ApplicationUser user = await _userManager.FindByEmailAsync(email);
var result = await _userManager.AddToRolesAsync(user, roles);
return result;
}
}
到 运行 启动时的代码。在路由配置之后的配置方法末尾的 Startup.cs 中,按照 Stafford Williams 之前所说的添加以下代码。
SampleData.Initialize(app.ApplicationServices);
以下行在 AspNetRoles table 中创建条目,但不填充 NormalizedName 列。
用以下内容替换要填充的此列:
RoleManager<IdentityRole> roleManager = serviceProvider.GetService<RoleManager<IdentityRole>>();
roleManager.CreateAsync(new IdentityRole(role));
截至撰写本文时,还没有用于植入数据库的插件,但您可以创建一个 class 并将其添加到您的容器中,以便在应用程序启动时执行相同的操作,此处我是这样做的,首先创建一个 class:
public class YourDbContextSeedData
{
private YourDbContext _context;
public YourDbContextSeedData(YourDbContext context)
{
_context = context;
}
public async void SeedAdminUser()
{
var user = new ApplicationUser
{
UserName = "Email@email.com",
NormalizedUserName = "email@email.com",
Email = "Email@email.com",
NormalizedEmail = "email@email.com",
EmailConfirmed = true,
LockoutEnabled = false,
SecurityStamp = Guid.NewGuid().ToString()
};
var roleStore = new RoleStore<IdentityRole>(_context);
if (!_context.Roles.Any(r => r.Name == "admin"))
{
await roleStore.CreateAsync(new IdentityRole { Name = "admin", NormalizedName = "admin" });
}
if (!_context.Users.Any(u => u.UserName == user.UserName))
{
var password = new PasswordHasher<ApplicationUser>();
var hashed = password.HashPassword(user, "password");
user.PasswordHash = hashed;
var userStore = new UserStore<ApplicationUser>(_context);
await userStore.CreateAsync(user);
await userStore.AddToRoleAsync(user, "admin");
}
await _context.SaveChangesAsync();
}
在 Startup.cs
的 ConfigureServices
方法中注册类型 class:
services.AddTransient<YourDbContextSeedData>();
接下来将 YourDbContextSeedData
class 传递给 Startup.cs
class 的 Configure
方法并使用它:
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory, YourDbContextSeedData seeder)
{
seeder.SeedAdminUser();
}
在模型命名空间中添加以下内容 class。它适用于添加多个用户和角色,并且还将为现有用户添加角色(例如 facbook 登录)。从 startup.cs
中这样称呼它app.SeedUsersAndRoles();
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNet.Builder;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.AspNet.Identity.EntityFramework;
using Microsoft.AspNet.Identity;
namespace MyApplication.Models
{
public static class DataSeeder
{
public static async void SeedUsersAndRoles(this IApplicationBuilder app)
{
var context = app.ApplicationServices.GetService<ApplicationDbContext>();
UserWithRoles[] usersWithRoles = {
new UserWithRoles("Admin", new string[] { "Administrator" , "Distributor" },"somepassword"),//user and optional roles and password you want to seed
new UserWithRoles("PlainUser"),
new UserWithRoles("Jojo",new string[]{"Distributor" }) //seed roles to existing users (e.g. facebook login).
};
foreach (var userWithRoles in usersWithRoles)
{
foreach (string role in userWithRoles.Roles)
if (!context.Roles.Any(r => r.Name == role))
{
var roleStore = new RoleStore<IdentityRole>(context);
await roleStore.CreateAsync(new IdentityRole(role));
}
var ExistingUser = context.Users.FirstOrDefault(p => p.NormalizedUserName == userWithRoles.User.NormalizedUserName);
if (ExistingUser == null) //the following syntax: !context.Users.FirstOrDefault(p => p.NormalizedUserName == userWithRoles.User.NormalizedUserName))
//provokes execption:(ExecuteReader requires an open and available Connection.)
await new UserStore<ApplicationUser>(context).CreateAsync(userWithRoles.User);
await app.AssignRoles(userWithRoles); //assign also to existing users.
}
context.SaveChangesAsync();
}
public static async Task<IdentityResult> AssignRoles(this IApplicationBuilder app, UserWithRoles uWR)
{
UserManager<ApplicationUser> _userManager = app.ApplicationServices.GetService<UserManager<ApplicationUser>>();
ApplicationUser user = await _userManager.FindByNameAsync(uWR.User.NormalizedUserName);
var result = await _userManager.AddToRolesAsync(user, uWR.Roles);
return result;
}
}
public class UserWithRoles
{
private ApplicationUser user;
public ApplicationUser User { get { return user; } }
public string[] Roles { get; set; }
public UserWithRoles(string name, string[] roles = null, string password = "secret")
{
if (roles != null)
Roles = roles;
else
Roles = new string[] { };
user = new ApplicationUser
{
Email = name + "@gmail.com", NormalizedEmail = name.ToUpper() + "@GMAIL.COM",
UserName = name, NormalizedUserName = name.ToUpper(),
PhoneNumber = "+1312341234",
EmailConfirmed = true,
PhoneNumberConfirmed = true,
SecurityStamp = Guid.NewGuid().ToString("D"),
};
user.PasswordHash = new PasswordHasher<ApplicationUser>().HashPassword(user, password);
}
}
}
所以这是基于 Muhammad Abdullah 回答的解决方案。包括一些代码改进、提高代码的可读性并让它与 .net core 2 一起工作。
public class Seed
{
public static async Task Initialize(IServiceProvider serviceProvider, IConfiguration configuration)
{
var usrName = configuration.GetSection("Admin").GetSection("UserName").Value;
var email = configuration.GetSection("Admin").GetSection("Email").Value;
var pass = configuration.GetSection("Admin").GetSection("Pass").Value;
var roles = new string[4] { OWNER, ADMIN, SENIOR, USER };
if(await CreateUser(serviceProvider, email, usrName, pass, roles))
{
await AddToRoles(serviceProvider, email, roles);
}
}
private static async Task<bool> CreateUser(IServiceProvider serviceProvider, string email, string usrName, string pass, string[] roles)
{
var res = false;
using (var scope = serviceProvider.CreateScope())
{
var context = scope.ServiceProvider.GetService<BaseContext>();
if (!context.ApplicationUsers.Any(u => u.NormalizedUserName == usrName.ToUpper()))
{
var roleStore = scope.ServiceProvider.GetService<RoleManager<IdentityRole>>();
foreach (string role in roles)
{
if (!context.Roles.Any(r => r.Name == role))
{
await roleStore.CreateAsync(new IdentityRole(role)).ConfigureAwait(false);
}
}
var user = new ApplicationUser
{
UserName = usrName,
Email = email,
EmailConfirmed = true,
NormalizedEmail = email.ToUpper(),
NormalizedUserName = usrName.ToUpper(),
PhoneNumber = null,
PhoneNumberConfirmed = true,
SecurityStamp = Guid.NewGuid().ToString()
};
var password = new PasswordHasher<ApplicationUser>();
user.PasswordHash = password.HashPassword(user, pass); ;
var userStore = new UserStore<ApplicationUser>(context);
res = (await userStore.CreateAsync(user).ConfigureAwait(false)).Succeeded;
}
return res;
}
}
private static async Task AddToRoles(IServiceProvider serviceProvider, string email, string[] roles)
{
using (var scope = serviceProvider.CreateScope())
{
var userManager = scope.ServiceProvider.GetService<UserManager<ApplicationUser>>();
var usr = await userManager.FindByEmailAsync(email).ConfigureAwait(false);
await userManager.AddToRolesAsync(usr, roles).ConfigureAwait(false);
}
}
}
如果您遇到异步问题,请尝试以下代码:
protected override void Seed(ApplicationDbContext context)
{
// This method will be called after migrating to the latest version.
string[] roles = new string[] { "Admin", "User" };
foreach (string role in roles)
{
if (!context.Roles.Any(r => r.Name == role))
{
context.Roles.Add(new IdentityRole(role));
}
}
//create user UserName:Owner Role:Admin
if (!context.Users.Any(u => u.UserName == "Owner"))
{
var userManager = new UserManager<ApplicationUser>(new UserStore<ApplicationUser>(context));
var user = new ApplicationUser
{
FirstName = "XXXX",
LastName = "XXXX",
Email = "xxxx@example.com",
UserName = "Owner",
PhoneNumber = "+111111111111",
EmailConfirmed = true,
PhoneNumberConfirmed = true,
SecurityStamp = Guid.NewGuid().ToString("D"),
PasswordHash = userManager.PasswordHasher.HashPassword("secret"),
LockoutEnabled = true,
};
userManager.Create(user);
userManager.AddToRole(user.Id, "Admin");
}
context.SaveChanges();
}
似乎这个线程很旧,但它仍然适用于想要在 entityframework 核心中播种身份表数据的人。
您可以简单地尝试以下操作。
modelBuilder.Entity<IdentityUser>().HasData(
new IdentityUser { Id= "-1", UserName="sagark",PasswordHash="sagark", Email="emailid goes here" }
);
您可以在 IdentityDbContext.cs 文件内的 OnModelCreating() 方法中播种用户和角色,如下所示。请注意,必须预定义密钥以避免每次执行此方法时都会播种新用户和角色。
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
//Seeding a 'Administrator' role to AspNetRoles table
modelBuilder.Entity<IdentityRole>().HasData(new IdentityRole {Id = "2c5e174e-3b0e-446f-86af-483d56fd7210", Name = "Administrator", NormalizedName = "ADMINISTRATOR".ToUpper() });
//a hasher to hash the password before seeding the user to the db
var hasher = new PasswordHasher<IdentityUser>();
//Seeding the User to AspNetUsers table
modelBuilder.Entity<IdentityUser>().HasData(
new IdentityUser
{
Id = "8e445865-a24d-4543-a6c6-9443d048cdb9", // primary key
UserName = "myuser",
NormalizedUserName = "MYUSER",
PasswordHash = hasher.HashPassword(null, "Pa$$w0rd")
}
);
//Seeding the relation between our user and role to AspNetUserRoles table
modelBuilder.Entity<IdentityUserRole<string>>().HasData(
new IdentityUserRole<string>
{
RoleId = "2c5e174e-3b0e-446f-86af-483d56fd7210",
UserId = "8e445865-a24d-4543-a6c6-9443d048cdb9"
}
);
}
aspnetcore中有IHostedService的概念。这使得 运行 异步背景成为可能 Task
.
@hamid-mosalla 的解决方案可以 async
并从 IHostedService
实现中调用。
种子 class 实现可能类似于
public class IdentityDataSeeder
{
private readonly UserManager<ApplicationUser> _userManager;
private readonly RoleManager<IdentityRole> _roleManager;
public IdentityDataSeeder(
UserManager<ApplicationUser> userManager,
RoleManager<IdentityRole> roleManager)
{
_userManager = userManager;
_roleManager = roleManager;
}
public async Task SeedAsync()
{
var superAdminRole = new IdentityRole
{
Id = "cac43a6e-f7bb-4448-baaf-1add431ccbbf",
Name = "SuperAdmin",
NormalizedName = "SUPERADMIN"
};
await CreateRoleAsync(superAdminRole);
var superAdminUserPassword = "P@ssword1";
var superAdminUser = new ApplicationUser
{
Id = "b8633e2d-a33b-45e6-8329-1958b3252bbd",
UserName = "admin@example.nl",
NormalizedUserName = "ADMIN@EXAMPLE.NL",
Email = "admin@example.nl",
NormalizedEmail = "ADMIN@EXAMPLE.NL",
EmailConfirmed = true,
};
await CreateUserAsync(superAdminUser, superAdminUserPassword);
var superAdminInRole = await _userManager.IsInRoleAsync(superAdminUser, superAdminRole.Name);
if (!superAdminInRole)
await _userManager.AddToRoleAsync(superAdminUser, superAdminRole.Name);
}
private async Task CreateRoleAsync(IdentityRole role)
{
var exits = await _roleManager.RoleExistsAsync(role.Name);
if (!exits)
await _roleManager.CreateAsync(role);
}
private async Task CreateUserAsync(ApplicationUser user, string password)
{
var exists = await _userManager.FindByEmailAsync(user.Email);
if (exists == null)
await _userManager.CreateAsync(user, password);
}
}
这可以从 IHostedService
:
public class SetupIdentityDataSeeder : IHostedService
{
private readonly IServiceProvider _serviceProvider;
public SetupIdentityDataSeeder(IServiceProvider serviceProvider)
{
_serviceProvider = serviceProvider;
}
public async Task StartAsync(CancellationToken cancellationToken)
{
using (var scope = _serviceProvider.CreateScope())
{
var seeder = scope.ServiceProvider.GetRequiredService<IdentityDataSeeder>();
await seeder.SeedAsync();
}
}
public Task StopAsync(CancellationToken cancellationToken) => Task.CompletedTask;
}
Startup
看起来像:
public void ConfigureServices(IServiceCollection services)
{
//...
services.AddHostedService<SetupIdentityDataSeeder>();
}
我的方式:
在模型文件夹中创建 Class
public static class ModelBuilderExtensions { public static void Seed(this ModelBuilder builder) { // Seed Roles List<IdentityRole> roles = new List<IdentityRole>() { new IdentityRole { Name = "Admin", NormalizedName = "ADMIN" }, new IdentityRole { Name = "User", NormalizedName = "USER" } }; builder.Entity<IdentityRole>().HasData(roles); // ----------------------------------------------------------------------------- // Seed Users var passwordHasher = new PasswordHasher<ApplicationUser>(); List<ApplicationUser> users = new List<ApplicationUser>() { // imporant: don't forget NormalizedUserName, NormalizedEmail new ApplicationUser { UserName = "user2@hotmail.com", NormalizedUserName = "USER2@HOTMAIL.COM", Email = "user2@hotmail.com", NormalizedEmail = "USER2@HOTMAIL.COM", }, new ApplicationUser { UserName = "user3@hotmail.com", NormalizedUserName = "USER3@HOTMAIL.COM", Email = "user3@hotmail.com", NormalizedEmail = "USER3@HOTMAIL.COM", }, }; builder.Entity<ApplicationUser>().HasData(users); ///---------------------------------------------------- // Seed UserRoles List<IdentityUserRole<string>> userRoles = new List<IdentityUserRole<string>>(); // Add Password For All Users users[0].PasswordHash = passwordHasher.HashPassword(users[0], "User.123"); users[1].PasswordHash = passwordHasher.HashPassword(users[1], "User.155"); userRoles.Add(new IdentityUserRole<string> { UserId = users[0].Id, RoleId = roles.First(q => q.Name == "User").Id }); userRoles.Add(new IdentityUserRole<string> { UserId = users[1].Id, RoleId = roles.First(q => q.Name == "Admin").Id }); builder.Entity<IdentityUserRole<string>>().HasData(userRoles); }}
在 DBContext
public class AppDbContext : IdentityDbContext<ApplicationUser> { public AppDbContext(DbContextOptions<AppDbContext> options) : base(options) { } protected override void OnModelCreating(ModelBuilder builder) { // Use seed method here builder.Seed(); base.OnModelCreating(builder); }}