Sauron
Sauron

Reputation: 2356

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

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:

public class ApplicationDbContext : IdentityDbContext<ApplicationUser>
{
    protected override void OnModelCreating(ModelBuilder builder)
    {
        // On event model creating
        base.OnModelCreating(builder);
    }
}

Please note ApplicationDbContext use IdentityDbContext and not DbContext.

There is any IdentityConfig.cs. Where i need to put the classic protected override void Seed to create role and user if it does not exist?

Upvotes: 73

Views: 100470

Answers (12)

Ragab Mohamad
Ragab Mohamad

Reputation: 708

By Using Extension Method.

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

OnModelCreating In DbContext

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

Upvotes: 3

Bahaa Samoudi
Bahaa Samoudi

Reputation: 183

My way:

  1. Create Class in models folder

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

Upvotes: 4

Orhan
Orhan

Reputation: 691

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 = "[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);
    }
}

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

Upvotes: 5

Hamza Dahmoun
Hamza Dahmoun

Reputation: 1304

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

    }

Upvotes: 54

Sagar Kalokhe
Sagar Kalokhe

Reputation: 64

Seems this thread is very old, but it will still work for someone who wants to seed their identity tables data in entityframework core.

You can simple try the below.

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

Upvotes: 1

Tracy Zhou
Tracy Zhou

Reputation: 734

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 = "[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();
    }

Upvotes: 5

Michal Ja
Michal Ja

Reputation: 252

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

Upvotes: 1

Muhammad Abdullah
Muhammad Abdullah

Reputation: 1102

My way of doing this is to create a class in models namespace.

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

}

To run this code on startup. In Startup.cs at end of configure method just after route configuration add following code as Stafford Williams said before.

SampleData.Initialize(app.ApplicationServices);

Upvotes: 94

Guy
Guy

Reputation: 1512

Add the following class in Models namespace. It works for adding multiple users and roles, and will also add roles to existing users (e.g. facbook logins). Call it like this app.SeedUsersAndRoles(); from 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);
        }
    }
}

Upvotes: 2

Arman Hamid Mosalla
Arman Hamid Mosalla

Reputation: 3355

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

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

Upvotes: 35

user3230113
user3230113

Reputation: 1

The following line create the entry in the AspNetRoles table but does not populate the NormalizedName column.

Substitute with the following for this column to be populated:

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

Upvotes: 0

Stafford Williams
Stafford Williams

Reputation: 9806

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.

Upvotes: 3

Related Questions