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のコードを見て、本当に無言だった.の
そこから得られたヒント:悪いデザインは多くの人に何年も叱られ、優秀なデザインは百世に名を残す.