ASP.NET FormsAuthenticationサイト間ログイン時に絶対アドレスが返される問題

3429 ワード


ASP.NETアプリケーションでは、FormsAuthenticationはほとんど標準設定されていますが、FormsAuthenticationは、現在のプログラムと同じサイトにないログインプログラムのシーンを考慮して設計されていません.このシーンの最も基本的なニーズは、別のサイトにログインに成功した後、元の場所に戻ることです.しかし、FormsAuthenticationは、ReturnUrlを渡す際に相対パスのみをサポートし、絶対アドレスもサポートせず、対応する拡張も提供していない.
例えば私たちはadminにいます.cnblogs.comサイトのweb.configでは、次のFormsAuthentication設定が行われています.
<authentication mode="Forms">
    <forms loginUrl="http://passport.cnblogs.com/login.aspx" timeout="2880" enableCrossAppRedirects="true"/>
</authentication>      
<authorization>
    <deny users="?" />
</authorization>

アクセスcnblogs.cc/Home/Indexはpassportにリダイレクトされます.cnblogs.com/login.aspx?ReturnUrl=%2 fHome%2 fIndex、これでログインして戻ってこない.
どうやってこの問題を解決しますか?
3つの方法が見つかりました.
方法1:現在のアプリケーションにログインジャンプページを追加し、web.configのloginUrlはこのジャンプボードを指し、ジャンプボードでReturnUrlの絶対アドレスを取得し、実際のログインページにリダイレクトします.
例えばASP.NET MVCでは、Controllerのアクションをジャンプボードとして使用できます.コードは次のとおりです.
public class LoginController : Controller 
{ 
    public ActionResult Redirect() 
    { 
        var loginUrl = "http://passport.cnblogs.com/login.aspx"; 
        var returnUrl = "?ReturnUrl=http://" + Request.Url.Host + Request.QueryString["ReturnUrl"]; 
        return RedirectPermanent(loginUrl + returnUrl); 
    } 
}

そしてweb.configのloginUrlはアクションを指します.
この方法の欠点は,リダイレクトを2回行うことである.
方法2:Global.asaxのApplication_PostAuthenticateRequestイベントではReturnUrlを絶対アドレスに設定し、ログインページにリダイレクトします.
コードは次のとおりです(コードはhttp://forums.asp.net/t/1358796.aspx):
        protected void Application_PostAuthenticateRequest(object sender, EventArgs e)
        {
            if (!UrlAuthorizationModule.CheckUrlAccessForPrincipal(Request.AppRelativeCurrentExecutionFilePath, Context.User, Request.RequestType)) 
            {
                Response.Redirect(String.Format("{0}?ReturnUrl={1}", 
                    FormsAuthentication.LoginUrl, Request.Url.AbsoluteUri)); 
            }
        }

方法3:Global.asaxのApplication_EndRequestイベントでResponseを変更する.RedirectLocationは、ReturnUrlを絶対アドレスに置き換えます.
コードは以下の通りです(コードはDavid Findley's Blogから来ています):
protected void Application_EndRequest(object sender, EventArgs e)
{
    string redirectUrl = this.Response.RedirectLocation;
    if (!string.IsNullOrEmpty(redirectUrl))
    {
        this.Response.RedirectLocation = Regex.Replace(redirectUrl,
            "ReturnUrl=(?'url'.*)", delegate(Match m)
            {
                string url = HttpUtility.UrlDecode(m.Groups["url"].Value);
                Uri u = new Uri(this.Request.Url, url);
                return string.Format("ReturnUrl={0}", HttpUtility.UrlEncode(u.ToString()));
            }, RegexOptions.Singleline | RegexOptions.IgnoreCase | RegexOptions.ExplicitCapture);
    }
}

この方法の欠点は,登録だけでなく,リダイレクトされたすべてのURLに対して処理を行うことである.
私たちが選んだのは2つ目の方法です.どうやってこの問題を解決したのですか.もっと良い方法はありませんか?
この問題はFormsAuthenticationの設計問題のせいで、当時この問題に遭遇して、マイクロソフトがこれを考慮していないとは信じられなかった.そしてFormsAuthenticationのコードを見て、本当に無言だった.の
そこから得られたヒント:悪いデザインは多くの人に何年も叱られ、優秀なデザインは百世に名を残す.