web-dev-qa-db-ja.com

ASP.NET Core 2.2 Create IdentityUser

ASP.Net Coreの真新しい。 Identityを使用してasp.netコア2.2プロジェクトを作成する必要があります(ユーザーをシードします)。

これを正確に行う方法に関するドキュメントは見つかりません。

Identity Rolesを作成するためのコードを見つけることができました(とにかくコンパイルされますが、まだ実行できる場所に達していません。

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

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

私が見るエラーは:

Argument1: 'Microsoft.AspNetCore.Identity.IdentityUser'から 'ApplicationDbContext'に変換できません

それは〜を意味しますか?明らかに、適切なuserManagerがありません。しかし、ユーザーを1番目のパラメーターとして、2番目の文字列(パスワード)を使用する正しいものを取得するにはどうすればよいですか?

さらに、Google検索で表示される例には、ApplicationUserオブジェクトがあり、私にはない(そして必要ないのですか?) )。取得方法については例で定義されていません。

オーウェン

OK。過去の構文エラーが発生しましたが、今度はランタイムエラーが発生します。

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

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

Create userManagerの他のパラメーターと、serviceProviderからそれらを取得する方法を調べますか?

-オーウェン

それを行う方法を考え出した。重要なのは、userManagerを作成するための正しい構文を渡すための正しいserviceproviderを見つけることでした。私がgoogle allを通じて見つけた他の回答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 = "[email protected]",
        Email = "[email protected]"
     };

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

あなたの主な問題は、依存性注入です。詳細は このリンク をご覧ください。 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 = "[email protected]";
        var users = context.Users;
        if (!context.Users.Any(u => u.UserName == username))
        {
            var done = await userManager.CreateAsync(new IdentityUser
            {
                UserName = username,
                Email = username
            }, username);
        }
    }

}
_

次に、スタートアップでservices.AddScoped<UserSeeder>()を使用して、このクラスをスコープとして追加する必要があります(DbContextがスコープであるため)。これで、UserSeederを任意のサービス(シングルトンを除く)に挿入し、UserSeeder関数を呼び出すことができます。たとえば、ホームコントローラーにUserSeederを挿入して、インデックスアクションと呼ぶことができます。このようにして、シードがチェックされ、最初に追加されます。ただし、これは最初にホームページに移動した場合にのみ機能します。または、スタートアップクラスで次のようなミドルウェアを設定することもできます。

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

これらの方法の両方で、毎回データベースを呼び出すことに注意してください。どこに配置するかを計画できます。また、ブール値(シングルトンの場合もある)を使用して、これが1回だけ呼び出されるようにすることもできます。ただし、これはアプリケーションの起動時にのみ実行されることに注意してください。

3

ここに私が私の管理ユーザーをシードする方法があります(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
    //...
}

Identityを使用する場合は、IdentityDbContextを使用し、カスタムUserおよびRoleクラスと、使用している主キーのタイプを指定する必要があります。

次のコードは、プログラムにIDを追加します。

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 == "[email protected]"))
                {
                    roleManager.CreateAsync(new Role()
                    {
                        Name = Role.Admin
                    })
                    .Wait();

                    userManager.CreateAsync(new User
                    {
                        UserName = "Admin",
                        Email = "[email protected]"
                    }, "secret")
                    .Wait();

                    userManager.AddToRoleAsync(userManager.FindByEmailAsync("[email protected]").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();
1
Sasan