我想知道是否有更好的方法来做到这一点:
假设我有角色为 "SuperUser" Admin "Manager" "Registered" 的用户。

在站点中注册的所有用户都具有“已注册”角色(例如,“经理”用户也具有“已注册”角色)。

现在我必须管理用户 Controller 上的 删除 操作。我想要达到的是:

  • “已注册”用户只能删除自己(例如:从站点注册中删除)
  • “管理员”用户可以删除自己和“注册”用户,bug 不能 删除“ super 用户”和“管理员”
  • “Admin”用户可以删除自己,“Managers”和“Registered”用户,bug 不能 删除“SuperUser”
  • "SuperUser"用户可以删除所有用户角色,甚至 super 用户。

  • 所以我从以下代码开始:
            [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
                }
    
            }
    
    

    我要做的是检查当前用户的每个角色与要删除的用户,但我真的不喜欢写很多“如果”....
    有没有办法做得更好?

    谢谢!

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

    最佳答案

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

    我不确定您的代码中的 _identityUser 是什么,但我假设 _identity 是 usermanager 存储库,而 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 集合的适当位置。

    关于c# - .NET MVC : Restrict action based on Role level,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/58024581/

    10-09 07:21