ASP.NET MVCで動的ログインURLにリダイレクトする方法


96

クライアントのページをホストするマルチテナントWebサイトを作成しています。URLの最初のセグメントは、次のURLルーティングスキーマを使用してGlobal.asaxで定義された、クライアントを識別する文字列になります。

"{client}/{controller}/{action}/{id}"

これは、/ foo / Home / IndexなどのURLで正常に機能します。

しかし、[Authorize]属性を使用すると、同じマッピングスキームを使用するログインページにリダイレクトしたいと思います。したがって、クライアントがfooの場合、ログインページは、web.configで定義された固定の/ Account / Loginリダイレクトではなく、/ foo / Account / Loginになります。

MVCはHttpUnauthorizedResultを使用して401無許可ステータスを返します。これにより、ASP.NETがweb.configで定義されたページにリダイレクトされると思います。

では、ASP.NETログインリダイレクトの動作をオーバーライドする方法を知っている人はいますか?または、カスタム認証属性を作成してMVCでリダイレクトする方が良いでしょうか?

編集-回答: .Netソースを少し調べた後、カスタム認証属性が最良のソリューションであると判断しました。

public class ClientAuthorizeAttribute: AuthorizeAttribute
{
    public override void OnAuthorization( AuthorizationContext filterContext )
    {
        base.OnAuthorization( filterContext );

        if (filterContext.Cancel && filterContext.Result is HttpUnauthorizedResult )
        {
            filterContext.Result = new RedirectToRouteResult(
                new RouteValueDictionary
                {
                    { "client", filterContext.RouteData.Values[ "client" ] },
                    { "controller", "Account" },
                    { "action", "Login" },
                    { "ReturnUrl", filterContext.HttpContext.Request.RawUrl }
                });
        }
    }
}

2
ルーティングとほぼ同じことを行うので、これが必要でした!ありがとう!
Trevor de Koekkoek、

ありがとう、私は同じようなことをする方法を理解しようとしていました。
チャンス

それは私自身の実装のアイデアを与えてくれました、本当にありがとう!
Alexander Beletsky、

3
MVC 2以上を使用している場合は、area = null(または正しい領域)を設定してください。そうしないと、アクセスしようとしたページから継承されます
Simon_Weaver

MVCなしでこれを行う方法はありますか?
DARKGuy 2014

回答:


30

主な問題は、組み込みのASP.NET FormsAuthenticationクラスに便乗する場合(そして、すべきでない理由がない場合)、1日の終わりに何かが呼び出さFormsAuthentication.RedirectToLoginPage()れるということです。 1つの構成済みURLを確認します。ログインURLは1つしかありません。それが、彼らが設計した方法です。

問題(おそらくRube Goldbergの実装)を試してみると、すべてのクライアントが共有するルートにある単一のログインページ(/ account / loginなど)にリダイレクトできるようになります。このログインページには実際には何も表示されません。ReturnUrlパラメータまたはセッションで取得した値、またはクライアントを識別するCookieを検査し、それを使用して特定の/ client / account / loginページへの即時302リダイレクトを発行します。これは追加のリダイレクトですが、おそらく目立たないため、組み込みのリダイレクトメカニズムを使用できます。

もう1つのオプションは、独自のカスタム属性を作成するときに作成RedirectToLoginPage()し、FormsAuthenticationクラスのメソッドを呼び出すものを回避します。これは、独自のリダイレクトロジックに置き換えるためです。(似たような独自のクラスを作成する場合があります。)これは静的クラスであるため、独自の代替インターフェースを挿入して、既存の[Authorize]属性と魔法のように連携させるメカニズムについては知りません。打撃が、人々は以前に同様のことをしたことがあります。

お役に立てば幸いです。


これはおそらく最も安全な方法です。独自の[MyAuthorize]属性を作成するのは危険です。ビルドが組み込みの[Authorize]属性を使用していないことを確認していない限り、ユーザー(または自分)が間違った属性を忘れて使用する危険性があります
Simon_Weaver

場合によってApplication_AuthenticateRequestは、オーバーライドすることが役立つ場合があります(以下の私の回答を参照)。
turdus-merula

41

ASP.NET MVCのRTMバージョンでは、Cancelプロパティがありません。このコードはASP.NET MVC RTMで動作します。

using System;
using System.Web;
using System.Web.Mvc;
using System.Web.Mvc.Resources;

namespace ePegasus.Web.ActionFilters
{
    public class CustomAuthorize : AuthorizeAttribute
    {
        public override void OnAuthorization(AuthorizationContext filterContext)
        {
            base.OnAuthorization(filterContext);
            if (filterContext.Result is HttpUnauthorizedResult)
            {
                filterContext.Result = new RedirectToRouteResult(
                    new System.Web.Routing.RouteValueDictionary
                        {
                                { "langCode", filterContext.RouteData.Values[ "langCode" ] },
                                { "controller", "Account" },
                                { "action", "Login" },
                                { "ReturnUrl", filterContext.HttpContext.Request.RawUrl }
                        });
            }
        }
    }
}

編集: web.configでデフォルトのフォーム認証loginUrlを無効にすることをお勧めします-誰かがカスタム属性を忘れて、組み込みの[Authorize]属性を誤って使用した場合。

web.configの値を変更します。

 <forms loginUrl="~/Account/ERROR" timeout="2880" />

次に、エラーをログに記録し、ユーザーを最も一般的なログインページにリダイレクトするアクションメソッド「ERROR」を作成します。


2
MVC 2以上を使用している場合は、必ず{area、null}をディクショナリ(または、エリアと呼ばれるもの)に追加してください。そうしないと、アクセスしようとしたページから継承されます
Simon_Weaver

2

この問題の私の解決策はカスタムActionResultクラスでした:

    sealed public class RequiresLoginResult : ActionResult
    {
        override public void ExecuteResult (ControllerContext context)
        {
            var response = context.HttpContext.Response;

            var url = FormsAuthentication.LoginUrl;
            if (!string.IsNullOrWhiteSpace (url))
                url += "?returnUrl=" + HttpUtility.UrlEncode (ReturnUrl);

            response.Clear ();
            response.StatusCode = 302;
            response.RedirectLocation = url;
        }

        public RequiresLoginResult (string returnUrl = null)
        {
            ReturnUrl = returnUrl;
        }

        string ReturnUrl { get; set; }
    }

0

それでも、組み込みのASP.NET FormsAuthenticationを使用する場合Application_AuthenticateRequestGlobal.asax.cs、次のようにオーバーライドできます。

protected void Application_AuthenticateRequest(object sender, EventArgs e)
{
    string url = Request.RawUrl;

    if (url.Contains(("Account/Login"))
    {
        return;
    }

    if (Context.User == null)
    {
        // Your custom tenant-aware logic
        if (url.StartsWith("/foo"))
        {
            // Your custom login page.
            Response.Redirect("/foo/Account/Login");
            Response.End();
            return;
        }
    }
}
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.