Si j'ai l'attribut Authorize à la fois sur le contrôleur et sur l'action, lequel prendra effet? Ou les deux entreront-ils en vigueur?
Tu as demandé:
Si j'ai l'attribut Authorize sur le contrôleur et l'action, lequel prendra effet? Tous les deux?
Pour répondre à cela simplement: les deux. L'effet est de AND
les deux restrictions ensemble. Je vais expliquer pourquoi ci-dessous ...
Donc, il y a quelques raisons pour lesquelles vous pourriez demander cela.
Vous n’avez pas spécifié votre version de MVC, je vais donc supposer la dernière en date (MVC 4.5). Cependant, cela ne changera pas beaucoup la réponse même si vous utilisiez MVC 3.
[Anonymous]
Remplace le contrôleur [Authorize]
(Cas 3)Cas 3. Je n'ai pas besoin de couvrir (l'utilisation de [AllowAnonymous]
) Car il a déjà été répondu sur tout SO et sur tout le Web déjà. Autant dire que si vous spécifiez [AllowAnonymous]
Pour une action, elle sera rendue publique même si le contrôleur a [Authorize]
Dessus.
Vous pouvez également soumettre un site Web entier à une autorisation par à l'aide d'un filtre global , et utiliser AllowAnonymous
sur les quelques actions ou contrôleurs que vous souhaitez rendre publics.
[Authorize]
Est additif (cas 1)Le cas 1 est facile. Prenons l'exemple du contrôleur suivant:
[Authorize(Roles="user")]
public class HomeController : Controller {
public ActionResult AllUsersIndex() {
return View();
}
[Authorize(Roles = "admin")]
public ActionResult AdminUsersIndex() {
return View();
}
}
Par défaut, [Authorize(Roles="user")]
rend toutes les actions du contrôleur disponibles pour les comptes du rôle "utilisateur" uniquement. Par conséquent, pour accéder à AllUsersIndex
, vous devez être dans le rôle "utilisateur". Cependant, pour accéder à AdminUsersIndex
, vous devez être à la fois dans les rôles "utilisateur" et "admin". Par exemple:
AdminUsersIndex
, mais peut accéder à AllUsersIndex
AdminUsersIndex
ou AllUsersIndex
AdminUsersIndex
et AllUsersIndex
.Cela montre que l'attribut [Authorize]
Est additif. Ceci est également vrai de la propriété Users
de l'attribut, qui peut être combinée avec Roles
pour la rendre encore plus restrictive.
Ce comportement est dû à la manière dont les attributs de contrôleur et d'action fonctionnent. Les attributs sont chaînés et appliqués dans le contrôleur d’ordre, puis à l’action. Si le premier refuse l'autorisation, le contrôle retourne et l'attribut de l'action n'est pas appelé. Si le premier passe l'autorisation, alors le second est également vérifié. Vous pouvez remplacer cet ordre en spécifiant Order
(par exemple [Authorize(Roles = "user", Order = 2)]
).
[Authorize]
(Cas 2)Le cas 2 est plus compliqué. Rappelons ci-dessus que les attributs [Authorize]
Sont examinés dans l'ordre (global puis) contrôleur puis action. Le premier à détecter que l'utilisateur n'est pas autorisé à être autorisé gagne, les autres ne sont pas appelés.
Une solution consiste à définir deux nouveaux attributs, comme indiqué ci-dessous. Le [OverrideAuthorize]
Ne fait que reporter à [Authorize]
; son seul but est de définir un type que nous pouvons vérifier. Le [DefaultAuthorize]
Nous permet de vérifier si l'action appelée dans la demande est décorée avec un [OverrideAuthorize]
. Si c'est le cas, nous passons au contrôle d'autorisation des actions, sinon nous procédons au contrôle au niveau du contrôleur.
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);
}
}
Nous pouvons ensuite l'utiliser comme ceci:
[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();
}
}
Dans l'exemple ci-dessus, SuperusersIndex
est disponible pour un compte doté du rôle "superutilisateur", même s'il ne possède pas le rôle "utilisateur".
J'aimerais ajouter quelque chose à Remplacer [Autoriser] (cas 2)
OverrideAuthorizeAttribute et DefaultAuthorizeAttribute fonctionnent bien, mais je découvre que vous pouvez également utiliser OverrideAuthorizationAttribute qui remplace les filtres d'autorisation définis à un niveau supérieur.
[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();
}
}
J'ai fait une adaptation de deuxième cas de cette réponse pour ASP.NET Core 2.1.
La différence avec AuthorizeAttribute
d'ASP.NET Core est qu'il n'est pas nécessaire d'appeler AuthorizeAttribute.OnAuthorization
méthode de base pour passer à l’autorisation normale. Cela signifie que même si vous n'appelez pas explicitement la méthode de base, la base AuthorizeAttribute
pourrait toujours court-circuiter l'autorisation en interdisant l'accès.
Ce que j'ai fait, c'est que j'ai créé un DefaultAuthorizeAttribute
qui n'hérite pas de AuthorizeAttribute
, mais de Attribute
à la place. Puisque DefaultAuthorizeAttribute
n'hérite pas de AuthorizeAttribute
, j'ai dû recréer le comportement d'autorisation.
[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) { }
}
Si vous l'utilisez sur le contrôleur, toutes les méthodes de ce contrôleur seront appliquées.
[Authorize]
public class SomeController(){
// all actions are effected
public ActionResult Action1
public ActionResult Action2
Si vous souhaitez empêcher l'une de ces actions, vous pouvez utiliser quelque chose comme ceci:
[Authorize]
public class SomeController(){
// all actions are effected
public ActionResult Action1
public ActionResult Action2
[AllowAnonymous]
public ActionResult Action3 // only this method is not effected...