c# - .NET MVC : Restrict action based on Role level

标签 c# asp.net-mvc authorization roles

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

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

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

  • “已注册”用户只能删除自己(即:从站点注册中删除)
  • “经理”用户可以删除自己和“注册”用户,错误不能删除“ super 用户”和“管理员”
  • “Admin”用户可以删除自己,“Managers”和“Registered”用户,错误不能删除“SuperUser”
  • “ super 用户”用户可以删除所有用户角色,甚至是 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 是用户管理器存储库和 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/

相关文章:

asp.net-mvc - 为服务层设计 DI(构造函数注入(inject))存储库

database - 批评我的身份验证系统数据库架构?

c# - ASP.NET 是否有更好的方法来查找其他控件内的控件?

javascript - 如何使用嵌套模型填充 Kendo UI 网格?

c# - WPF 桌面应用程序,Windows 10 Notification Toast 2016(UWP 社区工具包)

c# - 第二个参数没有传递给 Controller (ViewModel)

swift - 如何编写 GraphQL 查询

php - 将 PHP session_id 存储在 MySQL 中以进行 AJAX 授权?

c# - 使用 OAuth 连接到 Windows Azure Active Directory

c# - 我无法在字典中转换此实例