ASP.NET Identityを初めて使っています。
非常に便利なのですが、VisualStudioでMVCテンプレートを選択して作成したプロジェクトでは、IdentityUserを継承しているためにメールアドレスや電話番号等が含まれており、シンプルに名前とパスワードだけを使いたいような場合にはオーバースペックですよね。
そこで、生成したプロジェクトをベースに、必要最小限のユーザー情報で登録・ログインなどができるように変更してみたいと思います。
ApplicationUserをIUserを実装するように変更し、パスワードを追加します。
public class ApplicationUser : IUser
{
public string Id { get; set; }
public string UserName { get; set; }
public string PasswordHash { get; set; }
public async Task<ClaimsIdentity> GenerateUserIdentityAsync(UserManager<ApplicationUser> manager)
{
var userIdentity = await manager.CreateIdentityAsync(this, DefaultAuthenticationTypes.ApplicationCookie);
return userIdentity;
}
}
コンテキストをDbContext派生にします。
public class ApplicationDbContext : DbContext
{
public ApplicationDbContext()
: base("DefaultConnection")
{
}
public static ApplicationDbContext Create()
{
return new ApplicationDbContext();
}
public DbSet<ApplicationUser> ApplicationUsers { get; set; }
}
IUserStoreを実装するストアクラスを新しく作ります。
public class ApplicationUserStore : IUserStore<ApplicationUser>
{
private ApplicationDbContext _context;
public ApplicationUserStore(ApplicationDbContext context)
{
this._context = context;
}
// IUserStoreインターフェースの実装は省略
}
作成したストアをユーザーマネージャーのコンストラクタに渡します。
public class ApplicationUserManager : UserManager<ApplicationUser>
{
public ApplicationUserManager(IUserStore<ApplicationUser> store)
: base(store)
{
}
public static ApplicationUserManager Create(IdentityFactoryOptions<ApplicationUserManager> options, IOwinContext context)
{
var manager = new ApplicationUserManager(new ApplicationUserStore(context.Get<ApplicationDbContext>()));
// 省略
return manager;
}
}
これでビルドが通るようになりました。
デバッグを開始し、登録しようとするとエラーが発生します。
ストアは IUserPasswordStore<TUser> を実装していません。
{
var user = new ApplicationUser { UserName = model.Email, };
var result = await UserManager.CreateAsync(user, model.Password);
if (result.Succeeded)
{
|
ということで、ストアクラスにIUserPasswordStoreも実装します。
public class ApplicationUserStore : IUserStore<ApplicationUser>, IUserPasswordStore<ApplicationUser>
{
private ApplicationDbContext _context;
public ApplicationUserStore(ApplicationDbContext context)
{
this._context = context;
}
public void Dispose()
{
}
public Task<ApplicationUser> FindByNameAsync(string userName)
{
return this._context.ApplicationUsers.SingleOrDefaultAsync(x => x.UserName == userName);
}
public Task SetPasswordHashAsync(ApplicationUser user, string passwordHash)
{
return Task.Run(() => user.PasswordHash = passwordHash);
}
// その他のインターフェースの実装は省略
}
再度、登録しようとするとまたエラーが発生しました。
ストアは IUserEmailStore<TUser> を実装していません。
{
var user = new ApplicationUser { UserName = model.Email, };
var result = await UserManager.CreateAsync(user, model.Password);
if (result.Succeeded)
{
|
IUserPasswordStoreはまだしも、さすがにIUserEmailStoreを実装するわけにはいきません。
CreateAsyncメソッドをオーバーライドすることにしました。
public class ApplicationUserManager : UserManager<ApplicationUser>
{
public override async Task<IdentityResult> CreateAsync(ApplicationUser user, string password)
{
var store = (ApplicationUserStore)this.Store;
var identityResult = await UpdatePassword(store, user, password);
if (!identityResult.Succeeded)
{
return identityResult;
}
await store.CreateAsync(user);
return IdentityResult.Success;
}
}
ストアクラスの作成処理はこんな感じです。
public class ApplicationUserStore : IUserStore<ApplicationUser>, IUserPasswordStore<ApplicationUser>
{
public Task CreateAsync(ApplicationUser user)
{
user.Id = Guid.NewGuid().ToString();
this._context.ApplicationUsers.Add(user);
return this._context.SaveChangesAsync();
}
}
これで登録ができるようになりました。
次回はログインです。
またいつか、どこかで。