MVC角色授权

时间:2014-03-28 23:17:15

标签: asp.net-mvc asp.net-mvc-3 authorization

我正在尝试实现角色授权机制,该机制检查当前登录用户的角色,如果用户处于正确的角色,则允许他/她,否则显示错误视图。

问题是,当用户尝试访问控制器中的下面方法时,他确实进入RoleAuthorizationAttribute类并进行了验证,但是后来控制器中的方法没有被执行。

注意:用户具有客户端角色

控制器方法

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

角色身份验证类

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

    }
}

你能告诉我我做错了吗

3 个答案:

答案 0 :(得分:16)

由于我在数据库中拥有用户的角色,因此我必须检查数据库,因此我将此方法包含在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;
        }
    }

然后我可以使用正常的

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

在控制器中的actionResult方法之上

这很有用。

答案 1 :(得分:1)

如果您正在使用MVC 5,则必须在DbContext中启用延迟加载,方法是在DbContext初始化中添加以下行。

this.Configuration.LazyLoadingEnabled = true;

在MVC 5默认项目中,您将其添加到ApplicationDbContext.cs文件中。

我不确定这是否特定于MVC 5,Identity 2.0或影响其他版本。我正在使用此设置并启用延迟加载使所有默认角色架构都能正常工作。有关详细信息,请参阅https://stackoverflow.com/a/20433316/2401947

此外,如果您使用的是ASP.NET Identity 2.0默认权限架构,则不必像Darren所提到的那样实现Application_AuthenticateRequest。但是如果您使用的是自定义授权表,那么您也必须实现它。

答案 2 :(得分:1)

你的原始代码很接近,但问题出在这里:

base.OnAuthorization(filterContext);

无条件地调用基类意味着您需要在UsersService和内置角色提供程序中找到修饰的角色。如果角色提供程序未配置为返回相同的角色集(如果默认的AuthorizeAttribute对您不足,则不会这样做),这显然会导致授权测试始终返回false。

相反,您可以向派生属性添加单独的属性,例如

public string RemoteRoles { get; set; }

并替换

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

使用:

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

装饰你的控制器:

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