如何使用 Identity ASP.NET Core 通过代码优先迁移来播种用户和角色

问题描述 投票:0回答:13

我创建了一个新的干净的 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 放在哪里来创建角色和用户?

ef-code-first asp.net-identity asp.net-core-mvc seeding
13个回答
87
投票

我的方法是在模型命名空间中创建一个类。

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

46
投票

您可以在 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"
            }
        );
        

    }

34
投票
截至撰写本文时,还没有用于播种数据库的插件,但您可以创建一个类并将其添加到容器中,以便在应用程序启动时执行相同的操作,这是我的做法,首先创建一个类:

public class YourDbContextSeedData { private YourDbContext _context; public YourDbContextSeedData(YourDbContext context) { _context = context; } public async void SeedAdminUser() { var user = new ApplicationUser { UserName = "[email protected]", NormalizedUserName = "[email protected]", Email = "[email protected]", NormalizedEmail = "[email protected]", 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(); }

ConfigureServices

 类的 
Startup.cs
 方法中注册类型:

services.AddTransient<YourDbContextSeedData>();

接下来将

YourDbContextSeedData

 类传递给 
Configure
 类的 
Startup.cs
 方法并使用它:

public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory, YourDbContextSeedData seeder) { seeder.SeedAdminUser(); }
    

5
投票
如果您遇到异步问题,请尝试以下代码:

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

4
投票
在aspnetcore中有一个

IHostedService的概念。这使得运行异步后台成为可能Task

@hamid-mosalla 的解决方案可以制作

async

 并从 
IHostedService
 实现中调用。

种子类实现可能类似于

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

4
投票
我的方式:

  1. 在模型文件夹中创建类

    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 = "[email protected]", NormalizedUserName = "[email protected]", Email = "[email protected]", NormalizedEmail = "[email protected]", }, new ApplicationUser { UserName = "[email protected]", NormalizedUserName = "[email protected]", Email = "[email protected]", NormalizedEmail = "[email protected]", }, }; 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); }}
    
    
  2. 在 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); }}
    
    


2
投票
在 Models 命名空间中添加以下类。它适用于添加多个用户和角色,并且还会向现有用户添加角色(例如 facbook 登录)。像这样称呼它

app.SeedUsersAndRoles();

 来自startup.cs

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

1
投票
所以这是基于穆罕默德·阿卜杜拉答案的解决方案。包括一些代码改进,提高了代码的可读性并使其能够与 .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); } } }
    

1
投票
似乎这个线程很旧,但对于想要在实体框架核心中播种身份表数据的人来说,它仍然有效。

您可以简单尝试以下方法。

modelBuilder.Entity<IdentityUser>().HasData( new IdentityUser { Id= "-1", UserName="sagark",PasswordHash="sagark", Email="emailid goes here" } );
    

0
投票
以下行在 AspNetRoles 表中创建条目,但不填充 NormalizedName 列。

用以下内容替换要填充的此列:

RoleManager<IdentityRole> roleManager = serviceProvider.GetService<RoleManager<IdentityRole>>(); roleManager.CreateAsync(new IdentityRole(role));
    

0
投票

通过使用扩展方法。

namespace Course.Repository.Utilities { public static class AddRoleToAdmin { public static void ConfigurationUserAndRole(this ModelBuilder modelBuilder) { //Seeding a 'Administrator' role to AspNetRoles table modelBuilder.Entity<IdentityRole>().HasData( new IdentityRole() { Id = "2c5e174e-3b0e-446f-86af-483d56fd7210", Name = "Admin", NormalizedName = "Admin".ToUpper() } ); var hasher = new PasswordHasher<IdentityUser>(); // Seeding the User to AspNetUsers table modelBuilder.Entity<AppUser>().HasData( new AppUser() { Id= "8e445865-a24d-4543-a6c6-9443d048cdb9", UserName = "[email protected]", Email = "[email protected]", NormalizedUserName = "[email protected]".ToUpper(), NormalizedEmail = "[email protected]".ToUpper(), PasswordHash = hasher.HashPassword(null, "Admin123"), EmailConfirmed = true, LockoutEnabled = true, PhoneNumberConfirmed = true, SecurityStamp = Guid.NewGuid().ToString() } ); //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", // 2c5e174e-3b0e-446f-86af-483d56fd7210 UserId = "8e445865-a24d-4543-a6c6-9443d048cdb9" // 8e445865-a24d-4543-a6c6-9443d048cdb9 } ); } } }

在 DbContext 中创建模型

protected override void OnModelCreating(ModelBuilder modelBuilder) { base.OnModelCreating(modelBuilder); // Call Extension Method. modelBuilder.ConfigurationUserAndRole(); }
    

0
投票
现在我尝试在干净的架构 netcore 8 中播种数据,但失败了。 请帮我。 代码已上传至

https://github.com/nguyentuananh921/Learning.git 谢谢

© www.soinside.com 2019 - 2024. All rights reserved.