web-dev-qa-db-fra.com

Autorisation de rôle MVC

J'essaie d'implémenter un mécanisme d'autorisation de rôle qui vérifie les rôles de l'utilisateur actuellement connecté. Si l'utilisateur est dans le bon rôle, il/elle est autorisé (e), sinon la vue d'erreur est affichée.

Le problème est que lorsque l'utilisateur tente d'accéder à la méthode ci-dessous dans le contrôleur, il entre dans la classe RoleAuthorizationAttribute et est vérifié mais la méthode dans le contrôleur n'est pas exécutée. 

Remarque: l'utilisateur a le rôle de client 

Méthode du contrôleur 

[RoleAuthorization(Roles = "Client, Adminsitrator")]
    public ActionResult addToCart(int ProductID, string Quantity)
    {
        tempShoppingCart t = new tempShoppingCart();
        t.ProductID = ProductID;
        t.Username = User.Identity.Name;
        t.Quantity = Convert.ToInt16(Quantity);

        new OrdersService.OrdersClient().addToCart(t);
        ViewData["numberOfItemsInShoppingCart"] = new OrdersService.OrdersClient().getNoOfItemsInShoppingCart(User.Identity.Name);
        ViewData["totalPriceInSC"] = new OrdersService.OrdersClient().getTotalPriceOfItemsInSC(User.Identity.Name);
        return PartialView("quickShoppingCart", "Orders");
    }

Classe d'authentification de rôle 

[System.AttributeUsage(System.AttributeTargets.All,AllowMultiple = false, Inherited = true)]
public sealed class RoleAuthorizationAttribute : AuthorizeAttribute
{
    public override void OnAuthorization(AuthorizationContext filterContext)
    {


        List<String> requiredRoles = Roles.Split(Convert.ToChar(",")).ToList();

        List<Role> allRoles = new UsersService.UsersClient().GetUserRoles(filterContext.HttpContext.User.Identity.Name).ToList();


        bool Match = false;

        foreach (String s in requiredRoles)
        {
            foreach (Role r in allRoles)
            {
                string rName = r.RoleName.Trim().ToString();
                string sName = s.Trim();
                if (rName == sName)
                {
                    Match = true;
                }
            }
        }

        if (!Match)
        {
            filterContext.Result = new ViewResult { ViewName = "AccessDenied" };
        }

        base.OnAuthorization(filterContext);

    }
}

Pourriez-vous s'il vous plaît me dire ce que je fais mal 

13
drinu16

Comme j'avais les rôles des utilisateurs dans la base de données, j'ai dû vérifier par rapport à la base de données, donc j'ai inclus cette méthode dans le fichier global.asax.

protected void Application_AuthenticateRequest(object sender, EventArgs args)
    {
        if (Context.User != null)
        {
            IEnumerable<Role> roles = new UsersService.UsersClient().GetUserRoles(
                                                    Context.User.Identity.Name);


            string[] rolesArray = new string[roles.Count()];
            for (int i = 0; i < roles.Count(); i++)
            {
                rolesArray[i] = roles.ElementAt(i).RoleName;
            }

            GenericPrincipal gp = new GenericPrincipal(Context.User.Identity, rolesArray);
            Context.User = gp;
        }
    }

Ensuite, je pourrais utiliser la normale 

[Authorize(Roles = "Client, Administrator")]

En plus des méthodes actionResult dans les contrôleurs

Cela a fonctionné.

16
drinu16

Votre code d'origine était proche, mais le problème réside ici:

base.OnAuthorization(filterContext);

L'appel inconditionnel de la classe de base signifie que vous devez rechercher les rôles décorés à la fois dans le service d'utilisateurs et le fournisseur de rôles intégré. Si le fournisseur de rôle n'est pas configuré pour renvoyer le même ensemble de rôles (ce qui ne serait pas le cas si AuthorizeAttribute par défaut ne vous suffit pas), le résultat du test d'autorisation sera toujours toujours faux.

À la place, vous pouvez ajouter une propriété distincte à l’attribut dérivé, telle que 

public string RemoteRoles { get; set; }

et remplacer

 List<String> requiredRoles = Roles.Split(Convert.ToChar(",")).ToList();

avec:

 List<String> requiredRoles = RemoteRoles.Split(Convert.ToChar(",")).ToList();

Et décorez votre manette comme ceci:

[RoleAuthorization (RemoteRoles = "Client, Administrator")]
1
Henry Guillen

Si vous utilisez MVC 5, vous devez activer le chargement différé dans votre DbContext en insérant la ligne suivante dans votre initialisation DbContext.

this.Configuration.LazyLoadingEnabled = true;

Dans le projet par défaut de MVC 5, vous l'ajouterez au fichier ApplicationDbContext.cs.

Je ne sais pas si cela concerne MVC 5, Identity 2.0 ou d'autres versions. J'utilise cette configuration et j'active le chargement différé pour que tout le schéma de rôle par défaut fonctionne. Voir https://stackoverflow.com/a/20433316/2401947 pour plus d'informations.

De plus, si vous utilisez le schéma d'autorisation par défaut ASP.NET Identity 2.0, vous n'avez pas à implémenter Application_AuthenticateRequest comme l'a mentionné Darren. Mais si vous utilisez des tables d'autorisation personnalisées, vous devez également les implémenter.

1
fmoliveira