1. zaburo

    Posted

    zaburo
Changes in title
+ASP.NET Identity メモ
Changes in tags
Changes in body
Source | HTML | Preview
@@ -0,0 +1,263 @@
+
+ASP.NET Identityは利用する際の基本的なメモ。
+私のバカな頭では全体像がつかめなかったので、とりあえず簡単なユーザー登録、認証、Role等をテストしてみます。
+
+##認証用に利用するDBを作成する
+
+まず、ASP.NET Identityを利用した認証がとっつきにくいのはlocaldbに対して勝手にcode firstでテーブルが作られてしまうとこかなと。これはWeb.configのDefaultConnectionで設定されています。
+
+>なお、以下のコードは可動性重視?のためawait等は使わず同期処理で記述しています。
+
+
+###独自DBに変える
+
+本番だと普通はSQL Server使うと思うので変更します。
+
+```csharp
+public class ApplicationDbContext : IdentityDbContext<ApplicationUser>
+{
+ public ApplicationDbContext()
+ : base("DefaultConnection", throwIfV1Schema: false)
+ {
+ }
+
+ public static ApplicationDbContext Create()
+ {
+ return new ApplicationDbContext();
+ }
+}
+```
+
+DefaultConnectionの記述を変えてもいいと思いますし、新しいConnectionを定義して:base()を書き換えてもいいかと思います。
+
+###テーブルを生成する
+
+Code Firstで実行時に生成されるのはデモとしてはいいのですけど、実務では開発者の意図するタイミングで生成しておきたいこともあります。その場合は、Migrationしてやればいいようです。
+
+ツール -> NuGetパッケージマネージャー -> パッケージマネジャーコンソールを開き、
+
+```bash
+Enable-Migrations
+Add-Migration migration_filename
+Update-Database
+```
+
+で生成されます。
+
+>migration_filenameのところは適宜書き換えて下さい。
+
+生成されるデータベースは
+
+* AspNetRoles
+* AspNetUserClaims
+* AspNETUserLogins
+* AspNetUserRoles
+* AspNetUsers
+
+です。最低限必要なテーブルはAspNetUsersです。
+
+##DBにUserを登録する
+
+自動生成される登録画面を使う方法がよく紹介されていますが、汎用性が無いためコードで登録してみます。
+なお、標準の認証機構を利用する場合、最低限、
+
+* UserName(自動生成コードではEmailが挿入されるようになっているみたい)
+* Email
+* SecurityStamp
+
+の設定が必要となるようです。
+
+なお、ここでは標準で用意されているHomeControllerに、
+
+* ユーザーの追加 (createuser)
+* ログイン (login)
+* ログオフ (logoff)
+
+上記の3つのActionを実装してみたいと思います。
+
+###ModelsとIdentiryをusing
+
+必要な名前空間をusingします。
+
+###using
+
+必要な名前空間をusingします。Modelsは環境に合わせて変更して下さい。
+
+```csharp
+using System;
+using System.Web;
+using System.Web.Mvc;
+using Microsoft.AspNet.Identity;
+using Microsoft.AspNet.Identity.Owin;
+using Microsoft.Owin.Security;
+using APP_NAME.Models; //環境依存
+```
+
+###CreateUser
+
+普通にEntityFrameworkのINSERTと同じです。が、認証時のパスワードの突き合わせはハッシュ化されたパスワードを前提として行われるのでPasswordはHash化しておきます。またSecurityStampが無いと認証時に「オブジェクトがnullです!」的なエラーが出るのでとりあえず、Guidでも書き込んでおきます。
+
+```csharp
+public ActionResult CreateUser()
+{
+ //ユーザーの追加
+ var user = new ApplicationUser();
+
+ user.UserName = "test@test.com";
+ user.Email = "test@test.com";
+ //ハッシュ化する
+ user.PasswordHash = new PasswordHasher().HashPassword("test@test.com");
+ //SecurityStampを設定する(これがNullだと認証でエラーとなる)
+ user.SecurityStamp = Guid.NewGuid().ToString();
+
+ //追加処理
+ ApplicationDbContext adb = new ApplicationDbContext();
+ adb.Users.Add(user);
+ adb.SaveChanges();
+
+ //そのままサインイン処理
+ var signInManager = this.HttpContext.GetOwinContext().Get<ApplicationSignInManager>();
+ signInManager.SignIn(user, false, false);
+
+ return RedirectToAction("Index", "Home");
+}
+```
+
+ユーザーの生成と同時にログインさせていますが、必須ではありません。
+
+なお、生成の部分は、userManagerのCreateを利用することもできます(自動生成のregister actionは下記の様になっています)。
+
+```csharp
+//抜粋
+var user = new ApplicationUser { UserName = model.Email, Email = model.Email };
+var result = await UserManager.CreateAsync(user, model.Password);
+```
+
+##ログイン
+
+ユーザーが登録できたらログインしてみます。
+userManagerにより対象にユーザーの存在をチェックし、ユーザーがいたなら引き続き認証を行います。
+
+```csharp
+public ActionResult Login()
+{
+ //UserManager生成(ユーザーを検索するため:生成にも使える)
+ var userManager = this.HttpContext.GetOwinContext().GetUserManager<ApplicationUserManager>();
+ var user = userManager.Find("test@test.com", "test@test.com");
+
+ //SignInManager生成(認証するため)
+ var signInManager = this.HttpContext.GetOwinContext().Get<ApplicationSignInManager>();
+ signInManager.SignIn(user, false, false);
+
+ return RedirectToAction("Index","Home");
+}
+```
+
+##ログアウト
+
+AccountControllerを利用している場合はAuthenticationManager.SignOut()を呼び出すだけですが、別途実装すする場合は、IAuthenticationManagerを返すヘルパー関数?を用意してあげます(AccountControllerでそうなっているので)。
+
+```csharp
+public ActionResult Logoff()
+{
+
+ //サインアウト
+ AuthenticationManager.SignOut(DefaultAuthenticationTypes.ApplicationCookie);
+ return RedirectToAction("Index", "Home");
+}
+
+//ヘルパー
+private IAuthenticationManager AuthenticationManager
+{
+ get
+ {
+ return HttpContext.GetOwinContext().Authentication;
+ }
+}
+```
+
+ASP.NET Identiryの基本的な部分はこんな感じです。
+
+##Roleを使う
+
+###準備
+
+ロールを使うためにはまず、Models/IdentityModel.csに下記を追加します。
+
+```csharp
+//for role
+public class ApplicationRole : IdentityRole
+{
+
+}
+```
+
+###ロールの作成
+
+ロールを追加します。これによりAspNetRolesにadminが追加されます。
+
+```csharp
+public ActionResult CreateRole()
+{
+ //RoleManagerの取得
+ var roleManager = this.HttpContext.GetOwinContext().Get<ApplicationRoleManager>();
+ //Roleの生成
+ roleManager.Create(new ApplicationRole { Name = "admin"});
+
+ return Content("create role");
+}
+```
+
+###ユーザーの紐付け
+
+次にユーザーにRoleを紐付けます。ここでは既に登録したユーザーにadminを紐付けます。
+これによりAspNetUserRolesテーブルにuserIdとroleIdが登録され紐付けられます。
+
+```csharp
+public ActionResult CreateAdmin()
+{
+ //UserManagerの取得
+ var userManager = this.HttpContext.GetOwinContext().GetUserManager<ApplicationUserManager>();
+ //adminにするユーザーの検索
+ var user = userManager.Find("test@test.com", "test@test.com");
+ //紐づけ
+ userManager.AddToRole(user.Id, "admin");
+
+ return Content("create admin");
+}
+```
+
+###利用
+
+では、Roleを利用して表示やアクセスを制御してみます。
+
+####View
+
+ViweではIsInRole("rolename")を利用して表示の切り替え等を行うことができます。
+
+```html
+@if (Request.IsAuthenticated && HttpContext.Current.User.IsInRole("admin"))
+{
+ <h2>あなたは管理者です。</h2>
+}
+```
+
+####Controller
+
+Controllerではアノテーションを[Authorize(Roles ="rolename")]とすることでアクセスを制御することができます。
+
+```csharp
+//adminのみにアクセスを許可
+[Authorize(Roles ="admin")]
+public ActionResult AdminOnly ()
+{
+ return Content("こんにちはAdminさん。");
+}
+```
+
+##参考
+
+* http://blog.okazuki.jp/entry/2015/08/20/214212
+* http://blog.okazuki.jp/entry/2013/11/10/190811
+* http://kaz16a.hatenablog.jp/entry/2014/10/13/000843
+