ASP.NET Core 2.2 Create IdentityUser

故事扮演 提交于 2019-12-12 13:32:21

问题


Brand new to ASP.Net Core. Having to create an asp.net core 2.2 project with Identity (and have users seeded).

I can't find any documentation on how to do this exactly.

I was able to find the code to create Identity Roles (compiles anyway, haven't gotten to where I can run it yet:

  private static async Task CreateUserTypes(ApplicationDbContext authContext, IServiceProvider serviceProvider)
  {
     var RoleManager = serviceProvider.GetRequiredService<RoleManager<IdentityRole>>();
     string[] roleNames = { "Administrator", "Data Manager", "Interviewer", "Respondent" };
     IdentityResult roleResult;
     foreach (var roleName in roleNames)
     {
        var roleExist = await RoleManager.RoleExistsAsync(roleName);
        if (!roleExist)
        {
           roleResult = await RoleManager.CreateAsync(new IdentityRole(roleName));
        }
     }
  }

Now, I need to create some users. But the with the weird microsoft syntax to do that I can't find (been googling for 2 days).

Here's what does not work:

   private static async Task CreateRootUser(Models.CensORContext context, ApplicationDbContext authContext, IServiceProvider serviceProvider)
  {
     //Create the root ADMIN user for all things admin.
     UserManager<ApplicationDbContext> userManager = serviceProvider.GetRequiredService<UserManager<ApplicationDbContext>>();

     IdentityUser user = new IdentityUser()
     {
        UserName = "admin@admin.admin",
        Email = "admin@admin.admin"
     };

     var NewAdmin = await userManager.CreateAsync(user, "password");
  }

The error I see is:

Argument1: cannot convert from 'Microsoft.AspNetCore.Identity.IdentityUser' to 'ApplicationDbContext'

Does that mean? Obviously, I don't have the right userManager. But, how do I get the right one that takes a user as the 1st parameter and a string (password) for the 2nd?

In addition, the examples that come up in Google searches have an ApplicationUser object that I do not have (and don't need?). Not defined in the examples as to how I get it.

Owen

OK. Got past syntax error, but now I'm getting a runtime error:

NullReferenceException: Object reference not set to an instance of an object. on the call to CreateAsync. Here's the new code:

private static async Task CreateRootUser(Models.CensORContext context, ApplicationDbContext authContext, IServiceProvider serviceProvider)
{
     //Create the root ADMIN user for all things admin.         
     var userStore = new UserStore<IdentityUser>(authContext);
     UserManager<IdentityUser> userManager = new UserManager<IdentityUser>(userStore, null, null, null, null, null, null, serviceProvider, null);
     // = serviceProvider.GetRequiredService<UserManager<ApplicationDbContext>>();

     IdentityUser user = new IdentityUser()
     {
        UserName = "admin@admin.admin",
        Email = "admin@admin.admin"
     };

     var result = await userManager.CreateAsync(user, "password");
}

Going to be looking into what the other parameters are to the create userManager and how to get them from the serviceProvider?

--Owen

Figured out how to do it. The key was finding the correct serviceprovider to pass in and the right syntax for creating the userManager. The other answers I've found through google all replace the IdentityUser with their own ApplicationUser that was muddying the water. Here's the working function (hope this helps someone):

  private static async Task CreateRootUser(Models.CensORContext context, ApplicationDbContext authContext, IServiceProvider serviceProvider)
  {
     //Create the root ADMIN user for all things admin.         
     var userStore = new UserStore<IdentityUser>(authContext);
     UserManager<IdentityUser> userManager = serviceProvider.GetRequiredService<UserManager<IdentityUser>>();
     //new UserManager<IdentityUser>(userStore, null, null, null, null, null, null, serviceProvider, null);
     // = serviceProvider.GetRequiredService<UserManager<ApplicationDbContext>>();

     IdentityUser user = new IdentityUser()
     {
        UserName = "admin@admin.admin",
        Email = "admin@admin.admin"
     };

     var result = await userManager.CreateAsync(user, "password");
     result = await userManager.AddToRoleAsync(user, "Administrator");
  }

回答1:


Your main issue seems to be dependency injection. Have a look at this link for more information. As long as you inject your DbContext and UserManager in the right way and the rest of the code should be fine.

Here is an example. You can set up a separate service for seeding to ensure you decouple your code from the rest.

public class UserSeeder
{
    private readonly UserManager<IdentityUser> userManager;
    private readonly ApplicationDbContext context;

    public UserSeeder(UserManager<IdentityUser> userManager, ApplicationDbContext context)
    {
        this.userManager = userManager;
        this.context = context;
    }

    public async Task `()
    {
        string username = "admin@admin.admin";
        var users = context.Users;
        if (!context.Users.Any(u => u.UserName == username))
        {
            var done = await userManager.CreateAsync(new IdentityUser
            {
                UserName = username,
                Email = username
            }, username);
        }
    }

}

You then have to add this class as a scoped (since your DbContext is scoped) by using services.AddScoped<UserSeeder>() in your startup. You can now simply inject your UserSeeder in any service (except singletons) and call your UserSeeder function. For instance, You can inject UserSeeder in the home controller and call it index action. This way the seeding is checked and added initially. However, this will only work IF you go to the home page first. Alternatively, you can set up a middleware like this in your startup class:

app.Use(async (context, next) => {
    await context.RequestServices.GetService<UserSeeder>().SeedAsync();
    await next();
});

Note that both of these ways, you are calling the database every time. You can plan on where to place it. You can also make sure this is only called once with the help of a boolean (could be in a singleton). But note that this would only run on application startup.




回答2:


Here's how I seed my Admin user (learned from EF Core in Action book):

This is the User class:

public class User : IdentityUser<long>
{
    //add your extra properties and relations
}

The long type specifies the primary key type. If you use the default IdentityUser class it's going to be string (uniqueidentifier in SQL).

This is the Role class:

public class Role : IdentityRole<long>
{
    public static string Admin = "Admin";
}

It can be empty, I use static strings to avoid magic strings in my code.

This is the DbContext:

public class ApplicationDbContext : IdentityDbContext<User, Role, long>
{
    public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options)
        : base(options)
    { }

    //your DbSets and configurations
    //...
}

If you're going to use Identity, you need to use IdentityDbContext and specify your custom User and Role class and the type of primary key you're using.

This code adds Identity to the program:

public void ConfigureServices(IServiceCollection services)
{
    //...

    services.AddIdentity<User, Role>(options =>
        {
            //you can configure your password and user policy here
            //for example:
            options.Password.RequireDigit = false;
        })
        .AddEntityFrameworkStores<ApplicationDbContext>()
        .AddDefaultTokenProviders();

    //...
}

This is an extension method to seed data:

public static class SeedData
{
    public static IWebHost SeedAdminUser(this IWebHost webHost)
    {
        using (var scope = webHost.Services.CreateScope())
        {
            try
            {
                var context = scope.ServiceProvider.GetRequiredService<ApplicationDbContext>();
                context.Database.EnsureCreated();

                var userManager = scope.ServiceProvider.GetRequiredService<UserManager<User>>();
                var roleManager = scope.ServiceProvider.GetRequiredService<RoleManager<Role>>();

                if (!userManager.Users.Any(u => u.Email == "admin@domain.com"))
                {
                    roleManager.CreateAsync(new Role()
                    {
                        Name = Role.Admin
                    })
                    .Wait();

                    userManager.CreateAsync(new User
                    {
                        UserName = "Admin",
                        Email = "admin@domain.com"
                    }, "secret")
                    .Wait();

                    userManager.AddToRoleAsync(userManager.FindByEmailAsync("admin@domain.com").Result, Role.Admin).Wait();
                }                    
            }
            catch (Exception ex)
            {
                var logger = scope.ServiceProvider.GetRequiredService<ILogger<Program>>();
                logger.LogError(ex, "An error occurred while seeding user.");
                //throw;
            }
        }

        return webHost;
    }
}

And finally use it in your Program.cs:

CreateWebHostBuilder(args)
    .Build()
    .SeedAdminUser()
    .Run();


来源:https://stackoverflow.com/questions/53686409/asp-net-core-2-2-create-identityuser

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!