"技術的にできる" という実践例として 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 の フォロー」 お願いします!!
