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

Asp.net MVC4: コントローラとアクションの両方で認証する

2023-08-27 23:15:46

質問

コントローラとアクションの両方にAuthorize属性がある場合、どちらが効果を発揮するのでしょうか?それとも両方が効果を発揮するのでしょうか?

どのように解決するのですか?

という質問がありました。

コントローラとアクションの両方にAuthorize属性がある場合、どちらが効果を発揮するのでしょうか?両方ですか?

簡単にお答えすると 両方です。その効果は AND という2つの制限を一緒にしてしまうことです。以下にその理由を説明します.

詳細

では、このような質問をされる理由はいくつかあります。

  1. メソッドと比較して、アクションに追加の制約を強制する方法を知りたい場合。
    • コントローラレベルでは、ロール "user"のユーザーを強制する。
    • アクションレベルでは、さらに "admin" のロールのユーザーを強制します。
  2. アクションレベルでコントローラー制約を置き換えたい場合
  3. アクションレベルでのコントローラ制約を削除し、匿名ユーザーがメソッドを使用できるようにしたい。

MVCのバージョンが明記されていないので、今日現在の最新版(MVC 4.5)と仮定します。ただし、MVC 3 を使用していたとしても、回答はあまり変わりません。

[Anonymous] はコントローラをオーバーライドします。 [Authorize] (ケース3)

ケース3 カバーする必要がない(使用するのは [AllowAnonymous] ) が回答されているため SOの至る所で ウェブ上の至る所で を指定することができます。もしあなたが [AllowAnonymous] を指定すると、たとえコントローラがそのアクションを公開することになります。 [Authorize] がついていたとしても、そのアクションは公開されます。

また、ウェブサイト全体を認証の対象とするには、次のようにします。 グローバルフィルタを使って を使用し、さらに AllowAnonymous を使用してください。

[Authorize] は加算式(ケース1)

ケース1は簡単です。次のコントローラを例にとります。

[Authorize(Roles="user")]
public class HomeController : Controller {
    public ActionResult AllUsersIndex() {
        return View();
    }

    [Authorize(Roles = "admin")]
    public ActionResult AdminUsersIndex() {
        return View();
    }
}

デフォルトでは [Authorize(Roles="user")] は、Controller内の全てのActionを、"user"ロールのアカウントのみが利用できるようにします。そのため AllUsersIndex にアクセスするには、"user" ロールに属している必要があります。しかし AdminUsersIndex にアクセスするには、"user" と "admin" ロールの両方である必要があります。例えば

  • ユーザー名: Bob, ロール: user, はできません アクセス AdminUsersIndex にはアクセスできませんが AllUsersIndex
  • ユーザー名: Jane, ロール: admin, できません アクセス AdminUsersIndex または AllUsersIndex
  • ユーザー名: Tim, 役割: user & admin, できます アクセス AdminUsersIndexAllUsersIndex

これは [Authorize] 属性が加法的であることを示している。これは Users 属性のプロパティと組み合わせることができ、これは Roles と組み合わせることで、さらに制限を強めることができます。

この動作は、controller属性とaction属性の動作に起因しています。属性は連鎖しており、controller、actionの順で適用されます。もし最初のものが認可を拒否した場合、controlは戻り、actionの属性は呼び出されません。もし最初のものが認証を通れば、2 番目のものも同様にチェックされます。この順序を上書きするには Order (例えば [Authorize(Roles = "user", Order = 2)] ).

オーバーライド [Authorize] (ケース2)

ケース2はよりトリッキーです。上記から思い出してください。 [Authorize] 属性は (Global then) Controller, Action の順に検査されます。ユーザーが認証される資格がないことを最初に検出したものが勝利し、他のものは呼び出されないのです。

これを回避する一つの方法は、以下のように2つの新しい属性を定義することです。その [OverrideAuthorize] には何もせず、ただ [Authorize] その唯一の目的は、チェックすることができる型を定義することです。そのため [DefaultAuthorize] によって、リクエストの中で呼び出されるアクションが [OverrideAuthorize] . もしそうなら Action の認証チェックに進み、そうでなければ Controller レベルのチェックに進みます。

public class DefaultAuthorizeAttribute : AuthorizeAttribute {
    public override void OnAuthorization(AuthorizationContext filterContext)
    {
        var action = filterContext.ActionDescriptor;
        if (action.IsDefined(typeof(OverrideAuthorizeAttribute), true)) return;

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

すると、このように使うことができます。

[DefaultAuthorize(Roles="user")]
public class HomeController : Controller {
    // Available to accounts in the "user" role
    public ActionResult AllUsersIndex() {
        return View();
    }
    // Available only to accounts both in the "user" and "admin" role
    [Authorize(Roles = "admin")]
    public ActionResult AdminUsersIndex() {
        return View();
    }
    // Available to accounts in the "superuser" role even if not in "user" role
    [OverrideAuthorize(Roles = "superuser")]
    public ActionResult SuperusersIndex() {
        return View();
    }
}

上記の例では SuperusersIndex は、"user"ロールを持たないアカウントであっても、"superuser"ロールを持つアカウントで利用可能です。