it-swarm.com.de

MVC-Rollenberechtigung

Ich versuche, einen Rollenautorisierungsmechanismus zu implementieren, der die Rollen des aktuell angemeldeten Benutzers überprüft. Wenn der Benutzer die richtige Rolle hat, ist er erlaubt, oder er zeigt eine Fehleransicht an.

Das Problem ist, dass, wenn der Benutzer versucht, auf die unten stehende Methode im Controller zuzugreifen, er in die RoleAuthorizationAttribute-Klasse gelangt und überprüft wird, die Methode im Controller jedoch nicht ausgeführt wird. 

Hinweis: Der Benutzer hat die Client-Rolle 

Controller-Methode 

[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");
    }

Rollenauthentifizierungsklasse 

[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);

    }
}

Könnten Sie mir bitte sagen, was ich falsch mache? 

13
drinu16

Da ich die Rollen der Benutzer in der Datenbank hatte, musste ich die Datenbank überprüfen. Daher habe ich diese Methode in die Datei global.asax aufgenommen

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;
        }
    }

Dann könnte ich das normal gebrauchen 

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

Zusätzlich zu den actionResult-Methoden in den Controllern

Das hat funktioniert.

16
drinu16

Ihr ursprünglicher Code war knapp, aber das Problem liegt hier:

base.OnAuthorization(filterContext);

Bedingungsloses Aufrufen der Basisklasse bedeutet, dass Sie die dekorierten Rollen sowohl im UsersService als auch im integrierten Rollenanbieter finden müssen. Wenn der Rollenanbieter nicht so konfiguriert ist, dass er dieselbe Rollengruppe zurückgibt (was nicht der Fall wäre, wenn das Standard-AuthorizeAttribute für Sie nicht ausreicht), führt dies offensichtlich dazu, dass der Autorisierungstest immer false zurückgibt.

Stattdessen können Sie dem abgeleiteten Attribut eine separate Eigenschaft hinzufügen, wie z 

public string RemoteRoles { get; set; }

und ersetzen

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

mit:

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

Und schmücke deinen Controller so:

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

Wenn Sie MVC 5 verwenden, müssen Sie das verzögerte Laden in Ihrem DbContext aktivieren, indem Sie die folgende Zeile in Ihre DbContext-Initialisierung einfügen.

this.Configuration.LazyLoadingEnabled = true;

Im MVC 5-Standardprojekt fügen Sie es der ApplicationDbContext.cs-Datei hinzu.

Ich bin mir nicht sicher, ob dies für MVC 5, Identity 2.0 oder andere Versionen von Bedeutung ist. Ich verwende dieses Setup und aktiviere das langsame Laden, damit das Standardrollenschema funktioniert. Siehe https://stackoverflow.com/a/20433316/2401947 für weitere Informationen.

Wenn Sie das Standardberechtigungsschema von ASP.NET Identity 2.0 verwenden, müssen Sie Application_AuthenticateRequest nicht wie von Darren erwähnt implementieren. Wenn Sie jedoch benutzerdefinierte Autorisierungstabellen verwenden, müssen Sie diese ebenfalls implementieren.

1
fmoliveira