ASP.NET Core 2.2创建IdentityUser

时间:2018-12-08 19:56:54

标签: asp.net-core identity seeding asp.net-core-identity usermanager

ASP.Net Core的全新功能。必须使用Identity创建一个asp.net core 2.2项目(并为用户播种)。

我找不到任何有关如何准确执行此操作的文档。

我能够找到创建身份角色的代码(无论如何都可以编译,还没到我可以运行它的地方:

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

现在,我需要创建一些用户。但是我无法找到带有奇怪的Microsoft语法的代码(谷歌搜索了2天)。

这是不起作用的作用:

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

我看到的错误是:

  

参数1:无法从“ Microsoft.AspNetCore.Identity.IdentityUser”转换为“ ApplicationDbContext”

是什么意思?显然,我没有正确的userManager。但是,如何获取正确的参数,该参数将用户作为第一个参数,并将用户名作为第二个字符串(密码)?

此外,Google搜索中出现的示例中有一个我没有(也不需要?)的 ApplicationUser 对象。在示例中未定义如何获得它。

欧文

好。过去语法错误,但是现在我遇到了运行时错误:

  

NullReferenceException:对象引用未设置为对象的实例。在对CreateAsync的调用上。这是新代码:

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

要研究创建userManager的其他参数是什么以及如何从serviceProvider中获取它们?

-欧文

弄清楚如何做。关键是找到正确的服务提供商以传递用于创建userManager的正确语法。我在Google上找到的其他答案都用自己的IdentityUser 替换了ApplicationUser,这使水变得浑浊。这是工作功能(希望这对某人有帮助):

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

2 个答案:

答案 0 :(得分:3)

您的主要问题似乎是依赖注入。请查看this link了解更多信息。只要您以正确的方式注入DbContextUserManager,其余代码就可以了。

这里是一个例子。您可以为种子设置单独的服务,以确保将代码与其余代码分离。

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

}

然后,您必须在启动时使用DbContext将此类添加为作用域(因为services.AddScoped<UserSeeder>()是作用域)。现在,您可以简单地将UserSeeder注入任何服务(单例除外)并调用UserSeeder函数。例如,您可以在家庭控制器中注入UserSeeder并将其称为索引动作。这样可以检查种子并在最初添加种子。但是,仅当您首先进入主页时,此方法才有效。另外,您可以在启动类中设置这样的中间件:

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

请注意,这两种方式都是您每次都在调用数据库。您可以计划将其放置在何处。您也可以确保仅在布尔值的帮助下(仅在单例中)调用一次。但是请注意,这只能在应用程序启动时运行。

答案 1 :(得分:0)

这是我播种Admin用户的方式(从 EF Core in Action 书中学习):

这是User类:

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

long类型指定主键类型。如果您使用默认的IdentityUser类,它将是字符串(SQL中的唯一标识符)。

这是Role类:

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

它可以为空,我使用静态字符串来避免代码中出现魔术字符串。

这是DbContext

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

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

如果要使用身份,则需要使用IdentityDbContext并指定自定义UserRole类以及要使用的主键类型。

此代码将身份添加到程序中:

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

    //...
}

这是扩展种子数据的方法:

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

最后在您的Program.cs中使用它:

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