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 プロパティを使うのが便利そうです。