新しいクリーンなasp.net 5プロジェクト(rc1-final)を作成しました。 Identity Authenticationを使用すると、次のコードを含むApplicationDbContext.csが得られます。
public class ApplicationDbContext : IdentityDbContext<ApplicationUser>
{
protected override void OnModelCreating(ModelBuilder builder)
{
// On event model creating
base.OnModelCreating(builder);
}
}
ApplicationDbContextはDbContextではなくIdentityDbContextを使用することに注意してください。
IdentityConfig.csがあります。ロールとユーザーが存在しない場合、ロールとユーザーを作成するには、古典的な保護オーバーライドvoid Seedを配置する必要がありますか?
これを行う私の方法は、モデルの名前空間にクラスを作成することです。
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;
}
}
起動時にこのコードを実行します。ルート設定直後のconfigureメソッドの最後にあるStartup.csで、以前にStafford Williamsが言ったように次のコードを追加します。
SampleData.Initialize(app.ApplicationServices);
この記事の執筆時点では、データベースをシードするためのプラグインはありませんが、クラスを作成してコンテナに追加し、アプリの起動時に同じことを行うことができます。クラスを作成します。
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();
}
Startup.cs
クラスのConfigureServices
メソッドにタイプを登録します。
services.AddTransient<YourDbContextSeedData>();
次にYourDbContextSeedData
クラスをStartup.cs
クラスのConfigure
メソッドに渡し、使用します。
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory, YourDbContextSeedData seeder)
{
seeder.SeedAdminUser();
}
非同期の問題がある場合は、次のコードを試してください。
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();
}
これは まだ実装されていません です。回避策として、エンティティの存在をデータベースで確認する独自のクラスを作成し、存在しない場合はそれらを追加し、Startup.csからこのクラスを呼び出します。
Models名前空間に次のクラスを追加します。複数のユーザーとロールを追加するために機能し、既存のユーザーにロールを追加します(例:facbookログイン)。 startup.csからこのapp.SeedUsersAndRoles();
のように呼び出します
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);
}
}
}
したがって、これはムハンマド・アブドラの答えに基づく解決策です。いくつかのコードの改善、コードの読みやすさの改善が含まれ、.netコア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);
}
}
}
次の行は、AspNetRolesテーブルにエントリを作成しますが、NormalizedName列には入力しません。
この列にデータを入力するには、次のものに置き換えます。
RoleManager<IdentityRole> roleManager = serviceProvider.GetService<RoleManager<IdentityRole>>();
roleManager.CreateAsync(new IdentityRole(role));