How to Seed Users and Roles with Code First Migration using Identity ASP.NET Core

前端 未结 10 1545
离开以前
离开以前 2020-12-04 10:12

I have created a new clean asp.net 5 project (rc1-final). Using Identity Authentication I just have the ApplicationDbContext.cs with the following code:

publ         


        
相关标签:
10条回答
  • 2020-12-04 10:42

    If you have async issues, try the following code:

        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();
        }
    
    0 讨论(0)
  • 2020-12-04 10:50

    This is not yet implemented. As a work around, just write your own class that will check the database for the existence of your entities, add them if they don't exist, and call this class from your Startup.cs.

    0 讨论(0)
  • 2020-12-04 10:51

    In aspnetcore there is the concept of IHostedService. This makes it possible to run async background Task.

    The solution of @hamid-mosalla could be made async and called from an IHostedService implementation.

    Seed class implementation could be something like

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

    This can be called from an 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 would look like:

    public void ConfigureServices(IServiceCollection services)
    {
        //...
    
        services.AddHostedService<SetupIdentityDataSeeder>();
    }
    
    0 讨论(0)
  • 2020-12-04 10:56

    As of the time of this writing, there is no plug in place for seeding the database, but you can create a class and add it to your container to do the same thing on app start, here is how I've done it, first create a 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();
        }
    

    Register the type in ConfigureServices method of your Startup.cs class:

    services.AddTransient<YourDbContextSeedData>();
    

    Next pass the YourDbContextSeedData class to the Configure method of your Startup.cs class and use it:

    public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory, YourDbContextSeedData seeder)
    {
      seeder.SeedAdminUser();
    }
    
    0 讨论(0)
  • 2020-12-04 10:57

    So this is solution based on Muhammad Abdullah answer. Included few code improvements, improved readability of code and got it to work with .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);
                }           
            }
        }
    
    0 讨论(0)
  • 2020-12-04 11:00

    You can seed Users and Roles in OnModelCreating() method inside IdentityDbContext.cs file as shown below. Notice that the keys have to be predefined to avoid seeding new users and roles everytime this method is executed.

    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"
                }
            );
            
    
        }
    
    0 讨论(0)
提交回复
热议问题