コントローラーとアクションの両方にAuthorize属性がある場合、どちらが有効になりますか?または、両方が有効になりますか?
あなたが尋ねた:
コントローラーとアクションの両方にAuthorize属性がある場合、どちらが有効になりますか?両方?
これに単純に答えるには:両方。その効果は、2つの制限を一緒にAND
することです。以下にその理由を説明します...
そのため、これを尋ねる理由はいくつかあります。
MVCバージョンを指定しなかったため、今日の最新バージョン(MVC 4.5)を想定します。ただし、MVC 3を使用していても、答えはあまり変わりません。
[Anonymous]
はコントローラー[Authorize]
をオーバーライドします(ケース3)ケース3. SO全体 および Web全体 で既に回答されているため、([AllowAnonymous]
の使用)をカバーする必要はありません。言うだけで十分です:アクションで[AllowAnonymous]
を指定すると、コントローラーの[Authorize]
があっても、そのアクションがパブリックになります。
グローバルフィルターを使用 でWebサイト全体を承認の対象にし、公開するいくつかのアクションまたはコントローラーで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")]
は、コントローラーのすべてのアクションを「ユーザー」ロールのアカウントのみが使用できるようにします。したがって、AllUsersIndex
にアクセスするには、「ユーザー」ロールに属している必要があります。ただし、AdminUsersIndex
にアクセスするには、「user」ロールと「admin」ロールの両方である必要があります。例えば:
AdminUsersIndex
にアクセスできますが、AllUsersIndex
にはアクセスできますAdminUsersIndex
またはAllUsersIndex
にアクセスAdminUsersIndex
およびAllUsersIndex
これは、[Authorize]
属性が付加的であることを示しています。これは、属性の Users
プロパティにも当てはまります。これをRoles
と組み合わせて、さらに制限することができます。
この動作は、コントローラーとアクションの属性の動作方法によるものです。属性はチェーン化され、オーダーコントローラー、アクションに適用されます。最初のものが許可を拒否すると、制御が戻り、アクションの属性は呼び出されません。最初のものが認証に合格すると、2番目のものも同様にチェックされます。 Order
(たとえば、[Authorize(Roles = "user", Order = 2)]
)を指定することにより、この順序をオーバーライドできます。
[Authorize]
のオーバーライド(ケース2)ケース2は複雑です。上記から、[Authorize]
属性が(グローバル、次に)コントローラー、アクションの順に検査されることを思い出してください。ユーザーが許可される資格がないことを最初に検出したユーザーが勝ち、他のユーザーは呼び出されません。
これを回避する1つの方法は、次の2つの新しい属性を定義することです。 [OverrideAuthorize]
は、[Authorize]
に従うだけです。その唯一の目的は、チェックできる型を定義することです。 [DefaultAuthorize]
により、リクエストで呼び出されるActionが[OverrideAuthorize]
で装飾されているかどうかを確認できます。そうである場合は、アクション認証チェックに従います。それ以外の場合は、コントローラーレベルのチェックに進みます。
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
は、「スーパーユーザー」ロールを持つアカウントが、「ユーザー」ロールがない場合でも使用できます。
[Authorize]のオーバーライド(ケース2)に何かを追加したい
OverrideAuthorizeAttributeとDefaultAuthorizeAttributeは正常に機能しますが、上位レベルで定義された承認フィルターをオーバーライドするOverrideAuthorizationAttributeも使用できることを発見しました。
[Authorize(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
[OverrideAuthorization()]
[Authorize(Roles = "superuser")]
public ActionResult SuperusersIndex() {
return View();
}
}
ASP.NET Core 2.1用に この回答の2番目のケース を変更しました。
ASP.NET CoreのAuthorizeAttribute
との違いは、通常の認証に進むためにAuthorizeAttribute.OnAuthorization
基本メソッドを呼び出す必要がないことです。つまり、ベースメソッドを明示的に呼び出さなくても、ベースAuthorizeAttribute
はアクセスを禁止することにより、許可を短絡させる可能性があります。
私がしたことは、DefaultAuthorizeAttribute
からではなく、AuthorizeAttribute
から継承するAttribute
を作成したことです。 DefaultAuthorizeAttribute
はAuthorizeAttribute
から継承しないため、認証動作を再作成する必要がありました。
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = true)]
public class DefaultAuthorizeAttribute : Attribute, IAuthorizationFilter
{
private readonly AuthorizeFilter m_authorizeFilter;
public DefaultAuthorizeAttribute(params string[] authenticationSchemes)
{
var policyBuilder = new AuthorizationPolicyBuilder()
.AddAuthenticationSchemes(authenticationSchemes)
.RequireAuthenticatedUser();
m_authorizeFilter = new AuthorizeFilter(policyBuilder.Build());
}
public void OnAuthorization(AuthorizationFilterContext filterContext)
{
if (filterContext.ActionDescriptor is ControllerActionDescriptor controllerAction
&& controllerAction.MethodInfo.GetCustomAttributes(typeof(OverrideAuthorizeAttribute), true).Any())
{
return;
}
m_authorizeFilter.OnAuthorizationAsync(filterContext).Wait();
}
}
public class OverrideAuthorizeAttribute : AuthorizeAttribute, IAuthorizationFilter
{
public void OnAuthorization(AuthorizationFilterContext filterContext) { }
}
コントローラーで使用すると、このコントローラーのすべてのメソッドが影響を受けます。
[Authorize]
public class SomeController(){
// all actions are effected
public ActionResult Action1
public ActionResult Action2
これらのアクションのいずれかを防止する場合は、次のようなものを使用できます。
[Authorize]
public class SomeController(){
// all actions are effected
public ActionResult Action1
public ActionResult Action2
[AllowAnonymous]
public ActionResult Action3 // only this method is not effected...