Comment puis-je créer un AuthorizeAttribute personnalisé qui est spécifique à la région, le contrôleur et l'action?
En d'autres termes, est-ce vraiment une idée stupide?
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)]
public class AuthorizeActionAttribute : AuthorizeAttribute
{
public override void OnAuthorization(AuthorizationContext filterContext)
{
//get the area, controller and action
var area = filterContext.RouteData.Values["area"];
var controller = filterContext.RouteData.Values["controller"];
var action = filterContext.RouteData.Values["action"];
string verb = filterContext.HttpContext.Request.HttpMethod;
//these values combined are our roleName
string roleName = String.Format("{0}/{1}/{2}/{3}", area, controller, action, verb);
//set role name to area/controller/action name
this.Roles = roleName;
base.OnAuthorization(filterContext);
}
}
Mise à JOUR
J'essaie d'éviter le suivant, dans un scénario où nous avons très précise des rôles des autorisations parce que les rôles sont le programme d'installation sur une base par client et attaché à des groupes d'utilisateurs:
public partial class HomeController : Controller
{
[Authorize(Roles = "/supplierarea/homecontroller/indexaction/")]
public virtual ActionResult Index()
{
return View();
}
[Authorize(Roles = "/supplierarea/homecontroller/aboutaction/")]
public virtual ActionResult About()
{
return View();
}
}
Quelqu'un peut-il m'éclairer de manière sécurisée à écrire ce AuthorizeRouteAttribute pour accéder à la route de l'information et de l'utiliser comme le nom de rôle? Comme Lévi dit, la RouteData.Les valeurs n'est pas sécurisé.
Est l'utilisation de l'organe d'exécution httpContext.Demande.Chemin plus sécurisée ou de meilleures pratiques?
public override void OnAuthorization(AuthorizationContext filterContext)
{
if (filterContext == null)
{
throw new ArgumentNullException("filterContext");
}
if (!filterContext.HttpContext.User.Identity.IsAuthenticated)
{
//auth failed, redirect to login page
filterContext.Result = new HttpUnauthorizedResult();
return;
}
var path = filterContext.HttpContext.Request.Path;
var verb = filterContext.HttpContext.Request.HttpMethod;
//these values combined are our roleName
string roleName = String.Format("{0}/{1}", path, verb);
if (!filterContext.HttpContext.User.IsInRole(roleName))
{
//role auth failed, redirect to login page
filterContext.Result = new HttpUnauthorizedResult();
//P.S. I want to tell the logged in user they don't
//have access, not ask them to login. They are already
//logged in!
return;
}
//
base.OnAuthorization(filterContext);
}
Cette illustre peut-être la question un peu plus loin:
enum Version
{
PathBasedRole,
InsecureButWorks,
SecureButMissingAreaName
}
string GetRoleName(AuthorizationContext filterContext, Version version)
{
//
var path = filterContext.HttpContext.Request.Path;
var verb = filterContext.HttpContext.Request.HttpMethod;
//recommended way to access controller and action names
var controller =
filterContext.ActionDescriptor.ControllerDescriptor.ControllerName;
var action =
filterContext.ActionDescriptor.ActionName;
var area = "oh dear...."; //mmmm, where's thearea name???
//
var insecureArea = filterContext.RouteData.Values["area"];
var insecureController = filterContext.RouteData.Values["controller"];
var insecureAction = filterContext.RouteData.Values["action"];
string pathRoleName =
String.Format("{0}/{1}", path, verb);
string insecureRoleName =
String.Format("{0}/{1}/{2}/{3}",
insecureArea,
insecureController,
insecureAction,
verb);
string secureRoleName =
String.Format("{0}/{1}/{2}/{3}",
area,
controller,
action,
verb);
string roleName = String.Empty;
switch (version)
{
case Version.InsecureButWorks:
roleName = insecureRoleName;
break;
case Version.PathBasedRole:
roleName = pathRoleName;
break;
case Version.SecureButMissingAreaName:
//let's hope they don't choose this, because
//I have no idea what the area name is
roleName = secureRoleName;
break;
default:
roleName = String.Empty;
break;
}
return roleName;
}
OriginalL'auteur Rebecca | 2011-02-03
Vous devez vous connecter pour publier un commentaire.
Veuillez ne pas ce faire.
Si vous en avez vraiment besoin, vous pouvez utiliser le Type du contrôleur ou de la MethodInfo de l'action à prendre des décisions de sécurité. Mais, en fondant le tout hors tension des cordes est d'avoir des ennuis. Rappelez-vous, il n'y a aucune garantie de mappage 1:1 de Routage valeurs réelles contrôleur. Si vous êtes en utilisant le Routage tuple (a, b, c) pour valider l'accès à SomeController::Uneaction, mais que quelqu'un découvre que (a, b, c) frappe également que la même action, que personne ne peut ignorer vos mécanismes de sécurité.
Modifier pour répondre aux commentaires:
Vous avez accès au contrôleur du Type et de l'action MethodInfo via le filterContext du paramètre ActionDescriptor de la propriété. C'est le seul moyen infaillible pour déterminer quelle action vraiment exécuter lorsque le MVC pipeline est en cours de traitement, car il est possible que votre recherche ne correspond pas exactement ce qui se passe derrière les coulisses avec MVC. Une fois que vous avez le Type /MethodInfo ou autre, vous pouvez utiliser toutes les informations que vous souhaitez (comme leurs noms qualifiés complets) pour prendre des décisions de sécurité.
Comme un exemple concret, prenons une zone Monaire avec un contrôleur de FooController et une action TheAction. Normalement la façon dont vous frappez ce FooController::TheAction est via cette URL:
Et de Routage donne le n-uplet (Zone = "Monaire", Controller = "Foo", Action = "TheAction").
Cependant, vous pouvez également frapper les FooController::TheAction via cette URL:
Et le Routage donner le n-uplet (Zone = "", Controller = "Foo", Action = "TheAction"). Rappelez-vous, les domaines sont associés avec les routes, pas des contrôleurs. Et depuis un contrôleur peut être frappé par de multiples voies (si les définitions de match), un contrôleur peut également être liée logiquement à de multiples domaines. C'est pourquoi nous disons aux développeurs de ne jamais utiliser les routes (ou zones, ou de la <location> tag, par extension) à prendre des décisions de sécurité.
En outre, il y a un bug dans votre classe en ce qu'il est mutable (il mute son propre rôle de la propriété dans OnAuthorization). Action de filtrer les attributs doivent être immuables, car ils peuvent être mis en cache par les parties de la canalisation et réutilisés. Selon l'endroit où cet attribut est déclaré dans votre application, cela ouvre une attaque temporelle, un site malveillant visiteur peut ensuite exploiter pour s'octroyer l'accès à toute action qu'il souhaite.
Pour plus d'info, voir aussi mes réponses:
Mise à jour de la réponse à l'adresse de votre question.
Salut Levi, je comprends que je peux utiliser (string controller = filterContext.ActionDescriptor.ControllerDescriptor.ControllerName; string action = filterContext.ActionDescriptor.ActionName;) mais je ne peux pas accéder à la zone nom de la même manière. Cependant, il n'est pas AreaName disponibles. Où puis-je trouver cela? Un exemple de code simple serait de fermer cette question.
Aussi, en ce qui concerne le "bug dans votre classe en ce qu'il est mutable". Est-ce à dire que je devrais vérifier si l'utilisateur actuel dans le contexte IsInRole() moi-même et de rediriger si pas vrai?
Veuillez lire les articles que j'ai lié. Vous ne devrait pas être à l'aide de la région à prendre des décisions de sécurité. Pas d'exceptions. Le chose qu'une zone est utile pour est le partitionnement de votre site basé sur l'URL entrante. Depuis l'URL ne doit pas être utilisé pour prendre une décision de sécurité dans une application MVC, ni l'endroit. Vous avez besoin de retravailler la façon dont votre application de sécurité sont prises les décisions.
OriginalL'auteur Levi
Si vous voulez le faire, en prenant Levi's en compte de la recommandation, la réponse est comme suit:
Je n'ai pas envie de fournir un HttpUnauthorizedResult dans le cas d'un utilisateur de ne pas être dans le rôle, parce que le résultat est à envoyer à l'utilisateur à la page de connexion. Considérant qu'ils sont déjà connecté, ce qui est extrêmement déroutant pour l'utilisateur.
Comment supposez-vous que pour obtenir le
filterContext
dansAuthorizeCore
?Qu'est-ce que la question de l'appel de
base.OnAuthorization(filterContext);
à la fin de la mesure pour votreOnAuthorization()
?je me demandais pourquoi faire appel de la base.OnAuthorization(filterContext); lorsque vous êtes remplaçant?
href="http://stackoverflow.com/questions/1107022/should-i-call-the-base-class-implementation-when-overriding-a-method-in-c-sharp" title="dois-je appeler la classe de base de la mise en œuvre lors du remplacement d'une méthode en c sharp">stackoverflow.com/questions/1107022/...
OriginalL'auteur Rebecca
C'est un court avis! Assurez-vous d'utiliser
filterContext.RouteData.DataTokens["area"];
au lieu de
filterContext.RouteData.Values["area"];
Bonne Chance.
OriginalL'auteur QMaster