web-dev-qa-db-ja.com

ユーザーが承認されたロールに属していない場合、未承認のページを表示するにはどうすればよいですか?

私はAuthorize属性を次のように使用しています:

[Authorize (Roles="Admin, User")]
Public ActionResult Index(int id)
{
    // blah
}

ユーザーが指定されたロールにない場合、エラーページが表示されます(リソースが見つかりません)。それで、HandleError属性も入れました。

[Authorize (Roles="Admin, User"), HandleError]
Public ActionResult Index(int id)
{
    // blah
}

これで、ユーザーが指定されたロールにない場合、ログインページに移動します。

ユーザーが必要な役割の1つを満たさない場合に、ログインページではなくnauthorizedページに移動するにはどうすればよいですか?また、別のエラーが発生した場合、そのエラーを未承認のエラーと区別して、異なる方法で処理するにはどうすればよいですか?

41
Robert Harvey

次のようなものをweb.configに追加します。

<customErrors mode="On" defaultRedirect="~/Login">
     <error statusCode="401" redirect="~/Unauthorized" />
     <error statusCode="404" redirect="~/PageNotFound" />
</customErrors>

/PageNotFound/Unauthorizedのルート、アクション、ビューを作成する必要があります。

[〜#〜] edit [〜#〜]:すみません、問題を完全に理解していないようです。

問題は、AuthorizeAttributeフィルターが実行されると、ユーザーが要件に適合しないと判断することです(ユーザーはログインしている可能性がありますが、正しい役割ではありません)。したがって、応答ステータスコードを401に設定します。これは、リダイレクトを実行するFormsAuthenticationモジュールによってインターセプトされます。

2つの選択肢があります。

  1. DefaultRedirectを無効にします。

  2. 独自のIAuthorizationFilterを作成します。 AuthorizeAttributeから派生し、HandleUnauthorizedRequestをオーバーライドします。この方法では、ユーザーが認証されている場合、redirectを/ Unauthorizedに実行します

私も好きではありません。defaultRedirect機能はニースであり、自分で実装したいものではありません。 2番目の方法では、ユーザーに視覚的に正しい「あなたは認証されていません」ページが表示されますが、HTTPステータスコードは必要な401ではありません。

許容できるハックでこれを回避できるかどうかについては、HttpModulesについて十分に知りません。

編集2:次の方法で独自のIAuthorizationFilterを実装するのはどうですか。CodePlexからMVC2コードをダウンロードし、AuthorizeAttributeのコードを「借りる」。 OnAuthorizationメソッドを次のように変更します

    public virtual void OnAuthorization(AuthorizationContext filterContext)
    {
        if (AuthorizeCore(filterContext.HttpContext))
        { 
            HttpCachePolicyBase cachePolicy = filterContext.HttpContext.Response.Cache;
            cachePolicy.SetProxyMaxAge(new TimeSpan(0));
            cachePolicy.AddValidationCallback(CacheValidateHandler, null /* data */);
        }
        // Is user logged in?
        else if(filterContext.HttpContext.User.Identity.IsAuthenticated)
        {
            // Redirect to custom Unauthorized page
            filterContext.Result = new RedirectResult(unauthorizedUrl);
        } 
        else {
            // Handle in the usual way
            HandleUnauthorizedRequest(filterContext);
        }
    }

ここで、unauthorizedUrlはフィルターのプロパティか、Web.configから読み取られます。

AuthorizeAttributeを継承してOnAuthorizationをオーバーライドすることもできますが、すでにAuthorizeAttributeにあるいくつかのプライベートメソッドを作成することになります。

27
Rune

これは、次の2つの方法で実行できます。

  1. エラーのHandleError属性を指定し、表示する必要のあるビューを指定します。

    [HandleError(ExceptionType = typeof(UnAuthorizedException)、View = "UnauthorizedError")]

いくつかの異なるExceptionTypeとビューを指定できます

  1. カスタムActionFilterを作成し、そこで資格情報を確認し、ユーザーが無許可の場合はコントローラーにリダイレクトします。 http://web.archive.org/web/20090322055514/http://msdn.Microsoft.com/ en-us/library/dd381609.aspx
7
Pbirkoff

おそらく、403ステータスコードは、質問に基づいてより適切です(ユーザーは識別されますが、アカウントには十分な特権がありません)。 401は、ユーザーが持っている特権がわからない場合に使用します。

4
628426

そしてHttpUnauthorizedResult(これはAuthorizeAtrributeの再利用として提供されます)はStatusCodeを401に設定するだけです。したがって、おそらくIISまたはweb.config。もちろん、カスタムエラーページへのアクセスが承認を必要としないことを確認する必要もあります。

3
Mike Chaliy

AuthorizeAttributeのHandleUnauthorizedRequestメソッドをオーバーライドするだけです。このメソッドが呼び出されても、ユーザーIS=認証されている場合は、「承認されていない」ページにリダイレクトできます。

public class CustomAuthorizeAttribute : AuthorizeAttribute
{
    protected override void HandleUnauthorizedRequest(AuthorizationContext filterContext)
    {
        if (filterContext.HttpContext.User.Identity.IsAuthenticated)
        {
            filterContext.Result = new RedirectToRouteResult(new RouteValueDictionary(new { Area = "", Controller = "Error", Action = "Unauthorized" }));
        }
        else
        {
            base.HandleUnauthorizedRequest(filterContext);
        }
    }
}
0
Davy