C# .NET MVC:基于角色级别限制操作

C# .NET MVC:基于角色级别限制操作,c#,asp.net-mvc,authorization,roles,C#,Asp.net Mvc,Authorization,Roles,我想知道是否有更好的方法: 假设我有角色为“超级用户”,管理员,“经理”,“注册”的用户 在站点中注册的所有用户都具有“已注册”角色(例如,“经理”用户也具有“已注册”角色) 现在,我必须在用户控制器上管理删除操作。我想要达到的是: “已注册”用户只能删除自己(es:从站点注册中删除) “管理员”用户可以删除自己和“注册”用户,bug无法删除“超级用户”和“管理员” “管理员”用户可以删除自己、“管理员”和“注册”用户,bug无法删除“超级用户” “超级用户”用户可以删除所有用户角色,甚至超级

我想知道是否有更好的方法: 假设我有角色为“超级用户”管理员“经理”“注册”的用户

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

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

  • “已注册”用户只能删除自己(es:从站点注册中删除)
  • “管理员”用户可以删除自己和“注册”用户,bug无法删除“超级用户”和“管理员”
  • “管理员”用户可以删除自己、“管理员”和“注册”用户,bug无法删除“超级用户”
  • “超级用户”用户可以删除所有用户角色,甚至超级用户
因此,我从以下代码开始:

        [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.isInyRole(这是一个自定义函数,用于验证用户是否处于指定角色之一。

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

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

同样,您也可以通过创建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)]

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

我不确定代码中的
\u identity
User
是什么,但我假设
\u 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
}
//使用System.Collections.Generic;
//使用System.Linq;
//使用System.Security.Claims;
//此方法适用于所有经过身份验证的用户
[授权]
公共无效删除(int-id)
{
//测试当前用户是否要删除自身
if(User.FindFirst(ClaimTypes.UserData).Value!=id.ToString())
{
//查找当前用户的所有角色。
var roles=User.FindAll(“角色”).Select(r=>r.Value.ToList();
//按重要性排序的固定列表
var allowedRoles=新列表{“超级管理员”、“管理员”、“管理员”};
//当前用户的最高角色
var role=allowedRoles.Intersect(roles).FirstOrDefault();
//“已注册”用户不允许与其他用户进行任何操作
如果(角色==null)
返回;
//获取目标用户的角色名。类似于下面的内容,其中
//_identity是一个可以访问数据库的存储库(usermanager?)
var targetUserRoles=_identity.Where(u=>u.Id==Id).Roles().Select(r=>r.Name).ToList();
//var targetUserRoles=新列表{“Admin”};
//目标用户的最高角色,因为您不想删除
//当您是管理员时,既是管理员又是超级管理员的用户。
var targetUserRole=allowedRoles.Intersect(targetUserRoles.FirstOrDefault();
//可能会删除没有匹配角色的用户
if(targetUserRole!=null)
{
//确定两者作用的重要性
//当前用户和目标用户
var targetIndex=allowedRoles.IndexOf(targetUserRole);
var index=allowedRoles.IndexOf(角色);
//索引==0是超级管理员
//否则,targetuser的角色索引必须更高

如果(index>0&&targetIndex是,您假定用户和_标识正确):)出于某些原因,我需要一个“已注册”角色和一个“来宾”角色,但这并不重要。您的示例很好!谢谢。
[CustomAuthorize(Roles = Permissions.SuperAdmin | Permissions.Manager)]
// 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
}