.NET MVC:根据角色级别限制操作

.NET MVC: Restrict action based on Role level

我想知道是否有更好的方法: 假设我有角色为 "SuperUser"Admin"Manager" 的用户, "Registered".

站点中注册的所有用户都具有 "Registered" 角色(例如 "Manager" 用户也具有 "Registered" 角色)。

现在我必须管理用户控制器上的 Delete 操作。我想达到的是:

所以我从以下代码开始:

        [Authorize(Roles="Registered")]
        public void Delete(int id)
        {
            string[] AllowedRoles = { "SuperAdmin", "Manager" };

            if (_identity.FindFirst(ClaimTypes.UserData).Value == id.ToString())
            {
                //USER can delete himself!
                //TO DO: Deletion code
            }

            else if (User.IsInAnyRole(AllowedRoles))
            {
                //CHECK IF I CAN DELETE THE GIVEN USER
            }

        }

我要做的是检查当前用户的每个角色和要删除的用户,但我真的不喜欢写很多"if"... 有更好的方法吗?

谢谢!

PS:不用担心 User.IsInAnyRole(这是一个自定义函数,用于验证用户是否属于指定角色之一。

与我所做的类似的场景,而不是将角色作为字符串然后作为枚举标志

[Flags]
public enum Permissions
{
    None = 0,
    Registered = 1 << 0,
    SuperAdmin = 1 << 1,
    Manager = 1 << 2,
    // Etc...
}

然后,您可以使用此方法对用户确定允许哪些角色:

public bool IsInRole(Permissions roles)
{
    var rolesToCheck = roles.GetFlags().Where(p => p != Permissions.None);
    return rolesToCheck.Any(role => Roles.HasFlag(role));
}

和:

if(User.IsInRole(Permissions.SuperAdmin | Permissions.Manager)
{
    // Do something
}

同样,您也可以通过创建 Authorize 属性的自定义扩展将其添加到属性中:

public class CustomAuthorize : ActionFilterAttribute, IActionFilter
{
    public Permissions Roles { get; set; }

    void IActionFilter.OnActionExecuting(ActionExecutingContext filterContext)
    {
        bool authorized = false;
        var roleFlags = Roles.GetFlags();
        if (!roleFlags.All(r => r == Permissions.None))
        {
            foreach (var role in roleFlags.Where(p => p != RolePermissions.None))
            {
                if (maritimeUser.Roles.HasFlag(role))
                {
                    authorized = true;
                }
            }
        }

    if (Roles == Permissions.None)
    {
        // No roles set, so authorise = okay
        return;
    }

    if (!authorized)
    {
        filterContext.Result =
            new RedirectToRouteResult(
                new RouteValueDictionary
                {
                    {"controller", "Account"},
                    {"action", "Unauthorised"},
                    {"area", "" }
                });
        return;
    }
}

并由

使用
[CustomAuthorize(Roles = Permissions.SuperAdmin | Permissions.Manager)]

我想知道,是否有经过身份验证的用户不是 "registered"? IMO 这个角色不是必需的。如果您不同意,您可以修改下面的代码。

我不确定你的代码中的 _identityUser 是什么,但我假设 _identity 是用户管理器存储库,User 是当前的 httpcontext用户。我假设您需要 UserManager,因为如果不访问存储的声明(如 AspNetUserClaims),您将无法执行此测试。

请注意,我没有完全测试这段代码。

// using System.Collections.Generic;
// using System.Linq;
// using System.Security.Claims;

// This method is available for all authenticated users
[Authorize]
public void Delete(int id)
{
    // Test if current user wants to delete itself
    if (User.FindFirst(ClaimTypes.UserData).Value != id.ToString())
    {
        // Find all roles of the current user.
        var roles = User.FindAll("role").Select(r => r.Value).ToList();

        // A fixed list, ordered by importance
        var allowedRoles = new List<string> { "SuperAdmin", "Admin", "Manager" };
        // Highest role of the current user
        var role = allowedRoles.Intersect(roles).FirstOrDefault();

        // "Registered" user is not allowed to do anything with other users
        if (role == null)
            return;

        // Get the rolename(s) of the target user. Something like this, where
        // _identity is a repository (usermanager?) that has access to the database
        var targetUserRoles = _identity.Where(u => u.Id == id).Roles().Select(r => r.Name).ToList();
        //var targetUserRoles = new List<string> { "Admin" };

        // Highest role of the target user, because you don't want to delete
        // a user that is both Manager and SuperAdmin when you are Admin.
        var targetUserRole = allowedRoles.Intersect(targetUserRoles).FirstOrDefault();
        // Users without a matching role may be deleted
        if (targetUserRole != null)
        {
            // Determine the importance of the role of both
            // the current user and the target user
            var targetIndex = allowedRoles.IndexOf(targetUserRole);
            var index = allowedRoles.IndexOf(role);

            // Index==0 is SuperAdmin
            // Otherwise index of role of targetuser must be higher
            if (index > 0 && targetIndex <= index)
                return;
        }
    }

    // If we got here we can safely delete the user.

    //TO DO: Deletion code
}

如果您想扩展层次结构,只需将声明值添加到适当位置的 allowedRoles 集合即可。