1. ホーム
  2. asp.net-mvc

[解決済み】認証や認可に失敗した場合、AuthorizeAttributeがログインページにリダイレクトされるのはなぜですか?

2022-04-02 09:40:03

質問

ASP.NET MVCでは、コントローラメソッドのマークアップに AuthorizeAttribute のようなものです。

[Authorize(Roles = "CanDeleteTags")]
public void Delete(string tagName)
{
    // ...
}

これは、現在ログインしているユーザーが "CanDeleteTags" ロールでない場合、コントローラメソッドが決して呼び出されないことを意味します。

残念ながら、失敗の場合。 AuthorizeAttribute が返されます。 HttpUnauthorizedResult は、常にHTTPステータスコード401を返します。これはログインページへのリダイレクトを引き起こします。

ユーザーがログインしていない場合、これは完全に理にかなっています。しかし、もしユーザーが すでに ログインしているが、必要なロールを持っていない場合、ログインページに戻すと混乱する。

どうやら AuthorizeAttribute は、認証と認可を混同しています。

これはASP.NET MVCのちょっとした見落としのような気がするのですが、それとも何か見落としているのでしょうか?

を料理することになったんだ。 DemandRoleAttribute を分離しています。ユーザーが認証されていない場合、HTTP 401を返し、ログインページに送ります。ユーザーがログインしているが、必要なロールに属していない場合、HTTP 401を返し、ログインページに送ります。 NotAuthorizedResult 代わりに 現在、これはエラーページにリダイレクトされます。

確かに、こんなことする必要なかったかな?

解決方法は?

最初に開発されたとき、System.Web.Mvc.AuthorizeAttributeは正しいことを行っていました。 HTTP仕様の古いリビジョンでは、quot;unauthorized" と "unauthenticated" の両方にステータスコード401が使用されています。

元の仕様から。

<ブロッククオート

リクエストがすでに認証情報を含んでいた場合、401応答はそれらの認証情報に対して認証が拒否されたことを示す。

実際、ここに混乱が見られます。「認証」を意味するのに「認可」という言葉を使っているのです。しかし、日常的には、ユーザが認証されているが認可されていない場合に403 Forbiddenを返す方が理にかなっています。ユーザーがアクセスするための2つ目の認証情報を持っている可能性は低く、全体として悪いユーザーエクスペリエンスになります。

ほとんどのオペレーティングシステムを考えてみましょう。アクセス権限のないファイルを読もうとしたとき、ログイン画面は表示されません。

ありがたいことに、HTTPの仕様が更新(2014年6月)され、曖昧さが解消されました。

From "ハイパーテキストトランスポートプロトコル(HTTP/1.1)。Authentication" (RFC 7235)より。

<ブロッククオート

401(Unauthorized)ステータスコードは、ターゲットリソースに対する有効な認証情報がないため、リクエストが適用されなかったことを示す。

ハイパーテキスト転送プロトコル(HTTP/1.1)より。Semantics and Content" (RFC 7231)より。

<ブロッククオート

403(Forbidden)ステータスコードは、サーバーがリクエストを理解したが、それを承認することを拒否したことを示します。

興味深いことに、ASP.NET MVC 1がリリースされた時点では、AuthorizeAttributeの動作は正しかったのです。現在では、その動作は正しくありません。HTTP/1.1の仕様が修正されたのです。

ASP.NETのログインページのリダイレクトを変更しようとするよりも、問題を根本的に解決する方が簡単です。同じ名前の新しい属性を作成することができます ( AuthorizeAttribute ) を、あなたのウェブサイトのデフォルトの名前空間である (これは非常に重要です) そうすれば、コンパイラはMVCの標準的なものの代わりに、自動的にこれを選びます。もちろん、そのような方法を取りたいのであれば、いつでも新しい属性名を付けることができます。

[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, Inherited = true, AllowMultiple = true)]
public class AuthorizeAttribute : System.Web.Mvc.AuthorizeAttribute
{
    protected override void HandleUnauthorizedRequest(System.Web.Mvc.AuthorizationContext filterContext)
    {
        if (filterContext.HttpContext.Request.IsAuthenticated)
        {
            filterContext.Result = new System.Web.Mvc.HttpStatusCodeResult((int)System.Net.HttpStatusCode.Forbidden);
        }
        else
        {
            base.HandleUnauthorizedRequest(filterContext);
        }
    }
}