WebSurfer's Home

トップ > Blog 1   |   Login
Filter by APML

loginUrl に絶対 URL を指定した際の問題

by WebSurfer 18. June 2014 17:56

Fiddler2 で見たログインプロセス

web.config 内の forms 要素の loginUrl 属性に絶対 URL を指定した場合、ログイン後のリダイレクトがうまく行かないという問題と、その対応方法の紹介です。

左の画像はログインに成功して HTTP 302 応答が返ってきたところを Fiddler2 でキャプチャして見たものです。

クリックすると拡大画像が表示されますので、応答ヘッダ(右下のウィンドウ内)の Location に注目してください。本来 /Default.aspx であるべきところが /Account/Login.aspx になっています。

具体的にどういう問題かを以下に説明します。

ASP.NET Web Forms アプリケーションのフォーム認証で、Login コントロール を使った Login.aspx ページでログイン操作を行っているとします。

ログインに成功すると、Login.aspx の ReturnUrl クエリ文字列に指定されたページ(上の画像では /Default.aspx)か、クエリ文字列がない場合は forms 要素の defaultUrl 属性に指定されたページにリダイレクトされるのが普通の動作です。

ところが、以下のように loginUrl 属性に絶対 URL を指定すると、ログイン後に loginUrl 属性に指定した URL(即ち、/Account/Login.aspx ページ)にリダイレクトされてしまいます。← これが今回紹介する問題です。

<authentication mode="Forms">
  <forms loginUrl="http://<hostname>/Account/Login.aspx" />
</authentication>

何故そうなるかと言うと、Login.aspx でログイン成功後、認証クッキーを設定する HTTP 302 応答が帰ってきますが、応答ヘッダの Location が何故か ReturnUrl クエリ文字列(それがない場合は defaultUrl 属性の指定)を無視して /Account/Login.aspx となるからです。

上の画像で、左側のウィンドウ内で上から 4 番目の行がそのときの応答です。右下のウィンドウ内が応答ヘッダの内容で、その一番下の行 Location が /Account/Login.aspx となっています。ブラウザはこれを見て /Account/Login.aspx を GET 要求するという訳です。

なお、loginUrl 属性に相対 URL やルート演算子 (~) を使用した場合(例: loginUrl="~/Account/Login.aspx")は問題なく、期待通り ReturnUrl クエリ文字列に指定されたページにリダイレクトされます。

何故、絶対 URL を指定したいかと言えば forms 要素の requireSSL 属性 を True に設定して、認証 Cookie を送信するために SSL 接続を必須としたいからです。

その場合、loginUrl="https://<hostname>/Account/Login.aspx のように https で始まる絶対 URL を指定しないとサーバーエラーとなってログインできません。

ちなみに、loginUrl="~/Account/Login.aspx" requireSSL="true" とすると、Login.aspx ページは SSL 経由せずに表示されますが、ID とパスワードを入力して[ログイン]ボタンをクリックするとサーバーエラーとなり、以下のエラーメッセージが返ってきます。

"System.Web.HttpException: アプリケーションは、セキュリティで保護されたクッキーを発行するように構成されています。これらのクッキーでは、サーバーが SSL (https プロトコル) 経由で要求を発行することが必要ですが、現在の要求は SSL 経由ではありません。"

defaultUrl 属性の指定が無視されるという事例は聞いたことがありませんし、ググって調べても同様な事例は見つかりませんでした。

MSDN フォーラムASP.NET Forum で聞いてみましたが回答は得られませんでした。

というわけで、何故 loginUrl に絶対 URL を指定するとログイン後のリダイレクト先がその URL になってしまうかの原因は、現在のところ分かっていません。(汗)

この問題の解決方法ですが、原因が分かってないので対症療法的ではありますが、一応、以下の手段で回避できることは分かりました。

  1. Login コントロールを使わない。
  2. Login コントロールを使うなら、
    (1) Login.DestinationPageUrl プロパティでリダイレクト先を指定、または
    (2) Login.LoggedIn イベントで強制的にリダイレクトする。

上記 1 の具体的な例は FormsAuthentication.GetRedirectUrl メソッド のサンプルコードを見てください。

上記 2 の (2) の具体例は以下のコードを参考にしてください。

// LoggedIn イベントは、認証プロバイダによってユーザーの資格
// 情報がチェックされ、次の応答でブラウザに送信するために認証 
// Cookie がキューに置かれた後に発生。
protected void LoginUser_LoggedIn(object sender, EventArgs e)
{        
  string userName = LoginUser.UserName;
  string redirectUrl = 
      FormsAuthentication.GetRedirectUrl(userName, false);
  Response.Redirect(redirectUrl);

  // ちなみに以下ではいずれも問題は回避できないので注意。
  // Response.Redirect(redirectUrl, false);
  // FormsAuthentication.RedirectFromLoginPage(userName, false);
}

自分が検証に使った環境は以下の通りです。ASP.NET 4.5 で解決されているかどうかは分かりません。

  • ASP.NET 3.5 および 4
  • Vista 32-bit SP2 の IIS7
  • Visual Studio 2010 Professional
  • SQL Server 2008 Express で aspnetdb.mdf 使用
  • Login コントロールを使用
  • Web Forms アプリ(MVC は問題なし。たぶん Login を使わないため)

Tags:

Authentication

About this blog

2010年5月にこのブログを立ち上げました。その後 ブログ2 を追加し、ここは ASP.NET 関係のトピックス、ブログ2はそれ以外のトピックスに分けました。

Calendar

<<  July 2020  >>
MoTuWeThFrSaSu
293012345
6789101112
13141516171819
20212223242526
272829303112
3456789

View posts in large calendar