273

AuthorizeAttributeASP.NET MVC では、次のように、コントローラー メソッドを でマークアップできます。

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

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

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

ユーザーがログインしていない場合、これは完全に理にかなっています。ただし、ユーザーがすでにログインしているが、必要な役割を持っていない場合、ログイン ページに戻すのは混乱を招きます。

AuthorizeAttribute認証と承認を混同しているようです。

これは、ASP.NET MVC の見落としのように思えますが、何か不足しているのでしょうか?

私はDemandRoleAttribute2つを分離するものを調理しなければなりませんでした。ユーザーが認証されていない場合、HTTP 401 を返し、ログイン ページに送信します。ユーザーがログインしているが、必要な役割を持っていない場合は、NotAuthorizedResult代わりに を作成します。現在、これはエラー ページにリダイレクトされます。

きっと私はこれをする必要はありませんでしたか?

4

7 に答える 7

311

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

元の仕様から:

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

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

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

ありがたいことに、あいまいさを取り除くために HTTP 仕様が更新されました (2014 年 6 月)。

「ハイパー テキスト トランスポート プロトコル (HTTP/1.1): 認証」 (RFC 7235) から:

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

「ハイパーテキスト転送プロトコル (HTTP/1.1): セマンティクスとコンテンツ」(RFC 7231) から:

403 (Forbidden) ステータス コードは、サーバーが要求を理解したが、承認を拒否したことを示します。

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

ASP.NET のログイン ページのリダイレクトを変更しようとするよりも、問題の発生源を修正する方が簡単です。Web サイトのデフォルトの名前空間に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);
        }
    }
}
于 2011-04-30T22:00:22.260 に答える
24

これを Login Page_Load 関数に追加します。

// User was redirected here because of authorization section
if (User.Identity != null && User.Identity.IsAuthenticated)
    Response.Redirect("Unauthorized.aspx");

ユーザーがそこにリダイレクトされたが、すでにログインしている場合は、許可されていないページが表示されます。ログインしていない場合は、失敗してログイン ページが表示されます。

于 2009-04-01T13:29:29.310 に答える
4

残念ながら、ASP.NET フォーム認証の既定の動作を扱っています。ここで説明されている回避策があります(私は試していません):

http://www.codeproject.com/KB/aspnet/Custon401Page.aspx

(MVCに固有のものではありません)

ほとんどの場合、最善の解決策は、ユーザーがアクセスしようとする前に、許可されていないリソースへのアクセスを制限することだと思います。この許可されていないページに移動する可能性のあるリンクまたはボタンを削除またはグレー表示する。

許可されていないユーザーをリダイレクトする場所を指定するために、属性にパラメーターを追加するとよいでしょう。しかし当面は、AuthorizeAttribute をセーフティ ネットとして検討します。

于 2008-10-26T22:02:54.477 に答える
4

これは理にかなっているといつも思っていました。ログインしているときに、持っていないロールを必要とするページにアクセスしようとすると、そのロールを持つユーザーでログインするように求めるログイン画面に転送されます。

ユーザーがすでに認証されているかどうかを確認するロジックをログイン ページに追加できます。彼らが再びそこに戻ってきた理由を説明するフレンドリーなメッセージを追加できます.

于 2008-10-27T16:28:46.647 に答える
0

Global.ascx ファイルの Application_EndRequest ハンドラでこれを試してください

if (HttpContext.Current.Response.Status.StartsWith("302") && HttpContext.Current.Request.Url.ToString().Contains("/<restricted_path>/"))
{
    HttpContext.Current.Response.ClearContent();
    Response.Redirect("~/AccessDenied.aspx");
}
于 2015-01-08T21:44:27.313 に答える