SuppressFormsAuthenticationRedirect プロパティが便利だった件 - ROMANCE DAWN for the new world

ROMANCE DAWN for the new world

Microsoft Azure を中心とした技術情報を書いています。

SuppressFormsAuthenticationRedirect プロパティが便利だった件

.NET Framework 4.5 から追加された SuppressFormsAuthenticationRedirect プロパティが便利でした。フォーム認証を設定している ASP.NET MVC アプリと同じプロジェクトに ASP.NET Web API を実装した場合、Web API の Controller のアクションメソッドで HttpStatusCode.Unauthorized(401)を返しても、クライアント側には Location ヘッダーにログインページの URL が設定された HttpStatusCode.Found(302)に書き変えられた結果が返されます。Web API でこの動作だと都合が悪いときには、SuppressFormsAuthenticationRedirect プロパティに true をセットすると、HttpStatusCode.Unauthorized(401)を返すことができます。

前準備

Visual Studio から、ASP.NET Web API のプロジェクトを作成し、MVC アプリケーションにフォーム認証を設定します。

まず、HomeController クラスに Authorize 属性を付加します。

#HomeController.cs
[AllowAnonymous]
[Authorize]
public class HomeController : Controller
{
    public ActionResult Index()
    {
        return View();
    }
}

Web.config でフォーム認証を有効にします。

#Web.config
<system.web>
  <authentication mode="Forms">
    <forms loginUrl="/Account/Login/" />
  </authentication>
</system.web>

ログインとログアウトのアクションメソッドをもつ AccountController クラスと ビュー を実装します。

#AccountController.cs
[AllowAnonymous]
public class AccountController : Controller
{
    public ActionResult Login()
    {
        return View();
    }
 
    [HttpPost]
    [ValidateAntiForgeryToken]
    public ActionResult Login(string model)
    {
        FormsAuthentication.SetAuthCookie("Guest", false);
        return RedirectToAction("Index", "Home");
    }
 
    public ActionResult Logout()
    {
        FormsAuthentication.SignOut();
        return RedirectToAction("Login", "Account");
    }
}
#Login.cshtml
@{
    ViewBag.Title = "Login";
}
 
@using (Html.BeginForm())
{
    @Html.AntiForgeryToken()
    <div class="form-group">
        <input type="submit" value="Login" class="btn btn-default" />
    </div>
}

HttpStatusCode.Unauthorized(401)を返す Web API の TestController クラスを実装します。

#TestController.cs
public class TestController : ApiController
{
    [Route("api/test")]
    public IHttpActionResult Get()
    {
        return StatusCode(HttpStatusCode.Unauthorized);
    }
}

結果確認

プログラムを実行し、IE の F12 開発者ツールでキャプチャしてみます。GET api/test をリクエストすると、HttpStatusCode.Found(302)が返されてログインページにリダイレクトされていることが分かります。

302

SuppressFormsAuthenticationRedirect プロパティに true をセットするように変更し、再度プログラムを実行します。

#TestController.cs
public class TestController : ApiController
{
    [Route("api/test")]
    public IHttpActionResult Get()
    {
        HttpContext.Current.Response.SuppressFormsAuthenticationRedirect = true;
        return StatusCode(HttpStatusCode.Unauthorized);
    }
}

今度は、HttpStatusCode.Unauthorized(401)が返されるようになりました。

401

まとめ

いろいろと調べていると、FormsAuthenticationModule に書き換えられたステータスをカスタムモジュールで再度書き換える方法もありました。

.NET Framework 4.5 以降であれば、SuppressFormsAuthenticationRedirect プロパティを使うのが便利そうです。