"技術的にできる" という実践例として MVC 4 + WebAPI という組み合わせで、 RESTful like なフォーム認証を作る方法を記載します。 MVC だけで実装する フォーム認証 と比べ、実装量が増える デメリット がありますが、操作感が良くなる(リクエスト時に固まるをなくせる)メリットはあると思います。
目次
サンプルコード
概要
ちょっと強引かもしれませんが、MVC4 で画面表示のみ行い、ログイン と ログアウト を ASP.NET WebAPI で行う実装をしてみます。 完成時の挙動を下記のシーケンス図に示します。
- サイトへアクセス
- 未認証なので、ログインページ へ リダイレクト
- ユーザーID、パスワード を Ajax リクエスト
- 認証結果の返信し、認証済みのクッキーを設定
- もともとアクセスしようとしたページへ リダイレクト
上記について、具体的には次のような実装を行います。 2 のリダイレクトは web.config で実現します。 3 のログイン処理は jQuery を使って、 Ajax リクエスト を行います。 5 のリダイレクトは JavaScript で実現します。
以下では、それぞれについて詳細を掲載します。
作成する ファイル 、 フォルダ 構成
MVC4 + WebAPI で フォーム認証 を行おうとしたとき、以下のようなファイルを作っていきます。 今回は、それなりにコード記述が必要ですが…ブログ中では重要部分のみで、詳細は割愛します。
-
/web.config
認証と承認の設定を記述します。 -
/Controllers/AuthenticationController.cs
認証の実処理を行います。 -
/Controllers/HomeController.cs
秘匿するページ。 -
/Controllers/UserController.cs
ログインページ。
web.config の認証設定
Authentication (認証) は フォーム認証 で設定します。 Authorization (承認) は ホワイトリスト方式 (許可するものだけを記載する方式) で設定したいので、 ルートですべて拒否し、認証処理に必要な部分だけ許可するように設定します。
web.config (一部抜粋)
<configuration> <system.web> <authentication mode="Forms"> <forms loginUrl="/User/Login"></forms> </authentication> <authorization> <deny users="?"/> </authorization> </system.web> <location path="Scripts"> <system.web> <authorization> <allow users="*"/> </authorization> </system.web> </location> <location path="api/authentication"> <system.web> <authorization> <allow users="*"/> </authorization> </system.web> </location> </configuration>
ログイン、ログアウト 処理
ログイン、ログアウトは WebAPI で実装します。
以下には WebAPI の実装を掲載します。
やっていることは、受け取ったID、パスワードが正しいか判定して、正しければクッキーを発行する処理です。
認証済みであることを示すクッキーの発行、削除には FormsAuthentication クラス
を利用します。
AuthenticationController.cs
namespace MvcApplication.Controllers { using System; using System.Collections.Generic; using System.Linq; using System.Net; using System.Net.Http; using System.Web.Http; using System.Web.Security; using Models; public class AuthenticationController : ApiController { // // POST: /api/authentication/signin [HttpPost] public HttpResponseMessage SignIn(UserModel model) { if (model != null && model.Id == "hoge" && model.Password == "hoge") { FormsAuthentication.SetAuthCookie(model.Id, model.RememberMe); return this.Request.CreateResponse(HttpStatusCode.OK, new LoginResultModel() { IsSuccess = true, Message = "ログインに成功しました。" }); } else { return this.Request.CreateResponse(HttpStatusCode.Accepted, new LoginResultModel() { IsSuccess = false, Message = "ID または パスワード が違います。" }); } } // // POST: /api/authentication/signout [HttpPost] public HttpResponseMessage SignOut() { FormsAuthentication.SignOut(); return this.Request.CreateResponse(HttpStatusCode.OK); } } }
ログイン 処理への Ajaxリクエスト
ログイン、ログアウト処理は POST で受け付けるように構成したので、 jQuery でも POST で ログイン の リクエスト を行います。 ログイン リクエスト を行うと同時に、画面をリクエスト中である表示に切り替えます。 ここでは、複数回のリクエストを行わせないようにするため、 input要素 を無効化(非活性)にする処理のみ入れています。 画面上に「読み込み中」表示など追加で行っても良いと思います。
index.js (一部抜粋)
/** * submit ボタン 押下時に呼び出されます。 * @param {jQuery.Event} event jQuery イベントオブジェクト */ var submitbutton_onclick = function (event) { // ログイン リクエスト $.ajax({ type: 'POST', url: '/api/authentication/signin', data: { id: $('#id').val(), password: $('#password').val(), rememberMe: $('#rememberMe').prop('checked') }, success: ajax_onsuccess, error: ajax_onerror }); // input要素 を無効化 $('input').attr('disabled', 'disabled'); };
ログイン 後の リダイレクト
ログイン リクエスト が正常に返ってきた場合、所定の場所へ リダイレクト を行います。
リダイレクト先 は、クエリパラメター の ReturnUrl
に記載があるので、その値の場所へ window.location
を移動させます。
※ クエリ文字列の分解は こちら に記載しました。
index.js (一部抜粋)
/** * Ajax 通信が成功した際に呼び出されます。 * @param {object} data dataType に従って変換されたオブジェクト * @param {string} textStatus ステータス文字列 * @param {jqXHR} jqXHR XmlHttpRequest のラッパーオブジェクト */ var ajax_onsuccess = function (data, textStatus, jqXHR) { if (data.isSuccess) { // ログイン成功なので、リダイレクト window.location = query.ReturnUrl || '/'; } else { // ログイン失敗なので、input要素 を再度 有効化 $('input').removeAttr('disabled'); } };
最後に… このブログに興味を持っていただけた方は、 ぜひ 「Facebookページ に いいね!」または 「Twitter の フォロー」 お願いします!!