ASP.NET Core MVC - Cookie認証を試す
こちらのドキュメントを参考にしてIdentityを使わないCookie認証を試しました。
ASP.NET Core Identity なしでの cookie 認証を使用します。 | Microsoft Docs
Cookie認証はいわゆるフォーム認証だと思うんですが、もしかして今はそう言わないのかも。
仕組みや流れを理解するために最小限のサンプルコードを目指します。
Startupクラス
まずはStartupクラスのConfigureServicesメソッドとConfigureメソッドから見てみましょう。
Startup.ConfigureServices
ConfigureServicesメソッドでは、AddAuthenticationメソッドとAddCookieメソッドを使ってクッキー認証に必要なサービスを登録します。
また、AddMvcメソッドを使ってMVCに必要なサービスを登録しつつ、サイト全体にアクセス制御を設定するグローバルフィルタも追加しています。
public void ConfigureServices(IServiceCollection services) { // クッキー認証に必要なサービスを登録 services .AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme) .AddCookie(options => { // クッキーの名前を変える options.Cookie.Name = "auth"; // リダイレクトするログインURLも小文字に変える // ~/Account/Login => ~/account/login options.LoginPath = CookieAuthenticationDefaults.LoginPath.ToString().ToLower(); }); // MVCで利用するサービスを登録 services.AddMvc(options => { // グローバルフィルタに承認フィルタを追加 // すべてのコントローラでログインが必要にしておく var policy = new AuthorizationPolicyBuilder() .RequireAuthenticatedUser() .Build(); options.Filters.Add(new AuthorizeFilter(policy)); }); services.Configure<RouteOptions>(options => { // URLは小文字にする options.LowercaseUrls = true; }); }
正直なところAddAuthenticationに渡すスキーマについてはまだしっかり理解していない部分です。 ドキュメントにクッキー認証の複数のインスタンスとあったけど、外部IDでログインする場合も考慮するってこと?
Startup.Configure
Configureメソッドでは、UseAuthenticationメソッドで認証のミドルウェアをパイプラインを追加します。
このミドルウェアは、クッキーをもとに作ったプリンシパルをHttpContext.Userプロパティにセットしてくれるようです。
public void Configure(IApplicationBuilder app, IHostingEnvironment env) { if (env.IsDevelopment()) { app.UseDeveloperExceptionPage(); } // パイプラインに認証のミドルウェアを追加する // HttpContext.Userをセットしてくれる app.UseAuthentication(); // パイプラインにMVCのミドルウェアを追加する app.UseMvcWithDefaultRoute(); }
HomeController
今回のサンプルではコントローラを2つ用意します。
- HomeController...認証が必要なコントローラ
- AccountController...認証が不要でログインなどを行うコントローラ
まずは認証が必要なHomeControllerです。 Indexアクションを用意して、ログインしたユーザ名を表示するようにしておきます。
認証はグローバルフィルタで設定してあるので、コントローラに属性を設定する必要はありません。
// ログインが必要なコントローラ public class HomeController : Controller { public IActionResult Index() { // ユーザ名を表示する // User.Identity.Nameは"user01@example.jp" return Content(User.Identity.Name); } }
AccountController
AccountControllerでは3つのアクションを用意します。
- ログインビューを返すアクション
- ログイン処理(POST)のアクション
- ログアウト処理のアクション
1つずつ見ていきましょう。
ログインビューを返すアクションとログインビュー
グローバルフィルタで認証が設定されているので、アクションメソッドにAllowAnonymous属性を指定して匿名アクセスを許可します。
// ログインビュー [AllowAnonymous] public IActionResult Login() { return View(); }
ビューは本当ならログインIDとパスワードのinput要素があるのかなと思いますが、今回は省略して単純にPOSTするだけにしました。
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers <!DOCTYPE html> <html> <head> <meta name="viewport" content="width=device-width" /> <title>Login</title> </head> <body> <form asp-action="Login" method="post"> @* ログインIDやパスワードのinput要素は省略 *@ <button type="submit">ログイン</button> </form> </body> </html>
ログイン処理のアクション
ログイン処理のアクションの肝は、プリンシパルを作ってHttpContext.SignInAsyncメソッドを呼び出すところだと思います。
HttpContext.SignInAsyncメソッドを呼び出すと、認証クッキーをレスポンスに追加できます。
// ログインのポスト処理 [HttpPost] [AllowAnonymous] public async Task<IActionResult> Login(IFormCollection fromValues) { // サインインに必要なプリンシパルを作る // 本当ならユーザIDとパスワードからユーザを特定して・・・という処理が入るはず var claims = new[] { // 適当なユーザ名を登録しておく new Claim(ClaimTypes.Name, "user01@example.jp"), }; var identity = new ClaimsIdentity(claims, CookieAuthenticationDefaults.AuthenticationScheme); var principal = new ClaimsPrincipal(identity); // サインイン // 認証クッキーをレスポンスに追加 await HttpContext.SignInAsync(principal); // ログインが必要なアクションにリダイレクト return RedirectToAction("Index", "Home"); }
今回は適当なプリシンパルを作りました。 本当ならログインID/パスワードの検証やDBアクセスなどをすると思いますが省略しています。
ログアウト処理のアクション
最後にログアウト処理です。
HttpContext.SignOutAsyncメソッドを呼び出すと、レスポンスから認証クッキーを削除できます。
// ログアウト [AllowAnonymous] public async Task<IActionResult> Logout() { // サインアウト // 認証クッキーをレスポンスから削除 await HttpContext.SignOutAsync(); // ログインビューにリダイレクト return RedirectToAction("Login"); }
基本的なクッキー認証はこんな感じかなと思います。
動きとしては、まず~/home/index
にアクセスすると認証されていないので~/account/login
にリダイレクトされます。
~/account/login
にPOSTするとサインインして~/home/index
にリダイレクトされて、user01@example.jp
と表示されるようになります。
おしまい。