MVC Role Authorization

烈酒焚心 提交于 2019-12-20 08:49:53

问题


I am trying to implement a role authorization mechanism which checks the roles of the current logged in user, if the user is in the right role, he/she is allowed, else display error view.

The problem is that when the user tries to access the below method in the controller, he does get into the RoleAuthorizationAttribute class and gets verfied but then the method in the controller is not executed.

Note : the user has the Client role

Controller method

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

Role Authentication class

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

    }
}

Could you please tell me what I am doing wrong


回答1:


Since I had the roles of the users in the database I had to check against the database so I included this method in the 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;
        }
    }

Then I could use the normal

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

On top of the actionResult methods in the controllers

This worked.




回答2:


Your original code was close, but the problem lies here:

base.OnAuthorization(filterContext);

Unconditionally calling the base class means you are requiring the decorated roles to be found in BOTH the UsersService and the built-in Role provider. If the role provider isn't configured to return the same set of roles (which they wouldn't if the default AuthorizeAttribute isn't sufficient for you) then this will obviously result in the Authorization test always returning false.

Instead you could add a separate property to the derived Attribute such as

public string RemoteRoles { get; set; }

and replace

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

with:

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

And decorate your controller like such:

[RoleAuthorization (RemoteRoles = "Client, Administrator")]



回答3:


If you're using MVC 5 you have to enable lazy loading in your DbContext by putting the following line in your DbContext initialisation.

this.Configuration.LazyLoadingEnabled = true;

In MVC 5 default project you'll add it to ApplicationDbContext.cs file.

I'm not sure if this is particular to MVC 5, to Identity 2.0, or affect other versions. I'm using this setup and enabling lazy loading make all the default role schema works. See https://stackoverflow.com/a/20433316/2401947 for more info.

Additionally, if you're using ASP.NET Identity 2.0 default permission schema, you don't have to implement Application_AuthenticateRequest as Darren mentioned. But if you're using custom authorisation tables, then you have to implement it as well.



来源:https://stackoverflow.com/questions/22724798/mvc-role-authorization

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!