C#属性:使用枚举常量作为输入参数

时间:2022-11-27 14:30:33

I'm trying to implementing a new permission based access approach for my MVC application; We have several Permission Group and each group contains a list of Permission. for example we have Invoices permission group which contains CreateInvoice,RemoveInvoice,etc permission keys.

我正在尝试为我的MVC应用程序实现一种新的基于权限的访问方法;我们有几个权限组,每个组都包含一个权限列表。例如,我们有Invoices权限组,其中包含CreateInvoice,RemoveInvoice等权限密钥。

In this approach each mvc Action should requires a specific permission for execution. I'm trying to do this through CustomAttributes, something like this :

在这种方法中,每个mvc Action都需要特定的执行权限。我正在尝试通过CustomAttributes执行此操作,如下所示:

public class InvoiceController : Controller
    {
        [RequirePermission(Permissions.Invoices.CreateInvoice)]
        public ActionResult Create()
        {
            return View();
        }
    }

To make it easier for developers to remember different Permission Groups and Permission Keys I'm trying to create a pre-defined list of permissions that should be a combination of permission group and permission key. but due to restrictions applied to using attributes arguments in C# I couldn't make it work yet. (I don't want to make an extra large enumurator and put all permission keys in there)

为了让开发人员更容易记住不同的权限组和权限密钥,我正在尝试创建一个预定义的权限列表,该权限应该是权限组和权限密钥的组合。但由于在C#中使用属性参数的限制,我无法使其工作。 (我不想制作一个额外的大型枚举器并将所有权限密钥放在那里)

my last try was creating an enumerator for each permission group and then define permission keys as enum constants in there :

我的最后一次尝试是为每个权限组创建一个枚举器,然后将权限键定义为枚举常量:

public class PermissionEnums
{
    [PermissionGroup(PermissionGroupCode.Invoice)]
    public enum Invoices
    {
        CreateInvoice = 1,
        UpdateInvoice = 2,
        RemoveInvoice = 3,
        ManageAttachments = 4
    }

    [PermissionGroup(PermissionGroupCode.UserAccounts)]
    public enum UserAccounts
    {
        Create = 1,
        ChangePassword = 2
    }
}

As you can see we have a combination of codes here, the permission group key specified using a PermissionGroup attribute and permission key's code specified as numeral code on each enum constant.

正如您所看到的,我们在这里有代码组合,使用PermissionGroup属性指定的权限组密钥和在每个枚举常量上指定为数字代码的权限密钥代码。

the RequirePermission attribute defined as below :

RequirePermission属性定义如下:

public class RequirePermissionAttribute : Attribute
{
    private Enum _Permission;

    public RequirePermissionAttribute(Enum Permission)
        : base()
    {
        _Permission = Permission;
    }
}

but the problem is that objects of type Enum could not be used as Attribute Arguments.

但问题是Enum类型的对象不能用作属性参数。

Any suggestion/idea is appreciated

任何建议/想法都表示赞赏

2 个解决方案

#1


6  

I've found the solution, the only thing needs to be changed is type of constructure parameter. instead of using Enum you have to use object :

我找到了解决方案,唯一需要改变的是constructure参数的类型。而不是使用Enum你必须使用对象:

public class RequirePermissionAttribute : AuthorizeAttribute
{
    private object _Permission;

    public RequirePermissionAttribute(object Permission)
        : base()
    {
        _Permission = Permission;
    }
}

Here is the complete code :

这是完整的代码:

/***************** Permission Groups And Keys *****************/
public static class Permissions
{
    [PermissionGroup(PermissionGroupCode.Invoice)]
    public enum Invoices
    {
        CreateInvoice = 1,
        UpdateInvoice = 2,
        RemoveInvoice = 3,
        ManageAttachments = 4
    }

    [PermissionGroup(PermissionGroupCode.UserAccounts)]
    public enum UserAccounts
    {
        Create = 1,
        ChangePassword = 2
    }
}

public enum PermissionGroupCode
{
    Invoice = 1,
    UserAccounts = 2,
    Members = 3
}

/***************** Attributes & ActionFilters *****************/

[AttributeUsage(AttributeTargets.Enum)]
public class PermissionGroupAttribute : Attribute
{
    private PermissionGroupCode _GroupCode;
    public PermissionGroupCode GroupCode
    {
        get
        {
            return _GroupCode;
        }
    }

    public PermissionGroupAttribute(PermissionGroupCode GroupCode)
    {
        _GroupCode = GroupCode;
    }
}


public class RequirePermissionAttribute : AuthorizeAttribute
{
    private object _RequiredPermission;

    public RequirePermissionAttribute(object RequiredPermission)
        : base()
    {
        _RequiredPermission = RequiredPermission;
    }

    protected override bool AuthorizeCore(HttpContextBase httpContext)
    {
        var permissionGroupMetadata = (PermissionGroupAttribute)_RequiredPermission.GetType().GetCustomAttributes(typeof(PermissionGroupAttribute), false)[0];

        var groupCode = permissionGroupMetadata.GroupCode;
        var permissionCode = Convert.ToInt32(_RequiredPermission);

        return HasPermission(currentUserId, groupCode, permissionCode);
    }
}

#2


0  

I don't think thats possible I tried to do your thing and failed :/ sorry.

我不认为有可能我尝试做你的事情并且失败了:/抱歉。

Permissions on actions should be used with Authorize and you can make your own ovveride writing something like this:

有关操作的权限应与Authorize一起使用,您可以使用自己的ovveride编写如下内容:

    [AttributeUsage(AttributeTargets.All)]
    public sealed class CustomAuthorizeAttribute : AuthorizeAttribute
    {

   protected override bool AuthorizeCore(HttpContextBase httpContext)
    {
        if (httpContext == null)
            throw new ArgumentNullException("httpContext");

        //Its a piece of code from my app you can modify it to suit your needs or use the base one
        if (!new CustomIdentity(httpContext.User.Identity.Name).IsAuthenticated)
        {
            return false;
        }

        return true;
    }

    protected override void HandleUnauthorizedRequest(AuthorizationContext    filterContext)
    {
        base.HandleUnauthorizedRequest(filterContext);

     }

}

then on your action:

然后你的行动:

[CustomAuthorizeAttribute(Roles = "FE")]
public ActionResult Index()
{
    return RedirectToAction("Index", "Documents");
}

however its still a string that you use and for it to work you need to combine it with Custom Role provider. Much hussle but worth it in my opinion.

但是它仍然是您使用的字符串,并且要使其工作,您需要将其与自定义角色提供程序结合使用。很麻烦,但在我看来值得。

#1


6  

I've found the solution, the only thing needs to be changed is type of constructure parameter. instead of using Enum you have to use object :

我找到了解决方案,唯一需要改变的是constructure参数的类型。而不是使用Enum你必须使用对象:

public class RequirePermissionAttribute : AuthorizeAttribute
{
    private object _Permission;

    public RequirePermissionAttribute(object Permission)
        : base()
    {
        _Permission = Permission;
    }
}

Here is the complete code :

这是完整的代码:

/***************** Permission Groups And Keys *****************/
public static class Permissions
{
    [PermissionGroup(PermissionGroupCode.Invoice)]
    public enum Invoices
    {
        CreateInvoice = 1,
        UpdateInvoice = 2,
        RemoveInvoice = 3,
        ManageAttachments = 4
    }

    [PermissionGroup(PermissionGroupCode.UserAccounts)]
    public enum UserAccounts
    {
        Create = 1,
        ChangePassword = 2
    }
}

public enum PermissionGroupCode
{
    Invoice = 1,
    UserAccounts = 2,
    Members = 3
}

/***************** Attributes & ActionFilters *****************/

[AttributeUsage(AttributeTargets.Enum)]
public class PermissionGroupAttribute : Attribute
{
    private PermissionGroupCode _GroupCode;
    public PermissionGroupCode GroupCode
    {
        get
        {
            return _GroupCode;
        }
    }

    public PermissionGroupAttribute(PermissionGroupCode GroupCode)
    {
        _GroupCode = GroupCode;
    }
}


public class RequirePermissionAttribute : AuthorizeAttribute
{
    private object _RequiredPermission;

    public RequirePermissionAttribute(object RequiredPermission)
        : base()
    {
        _RequiredPermission = RequiredPermission;
    }

    protected override bool AuthorizeCore(HttpContextBase httpContext)
    {
        var permissionGroupMetadata = (PermissionGroupAttribute)_RequiredPermission.GetType().GetCustomAttributes(typeof(PermissionGroupAttribute), false)[0];

        var groupCode = permissionGroupMetadata.GroupCode;
        var permissionCode = Convert.ToInt32(_RequiredPermission);

        return HasPermission(currentUserId, groupCode, permissionCode);
    }
}

#2


0  

I don't think thats possible I tried to do your thing and failed :/ sorry.

我不认为有可能我尝试做你的事情并且失败了:/抱歉。

Permissions on actions should be used with Authorize and you can make your own ovveride writing something like this:

有关操作的权限应与Authorize一起使用,您可以使用自己的ovveride编写如下内容:

    [AttributeUsage(AttributeTargets.All)]
    public sealed class CustomAuthorizeAttribute : AuthorizeAttribute
    {

   protected override bool AuthorizeCore(HttpContextBase httpContext)
    {
        if (httpContext == null)
            throw new ArgumentNullException("httpContext");

        //Its a piece of code from my app you can modify it to suit your needs or use the base one
        if (!new CustomIdentity(httpContext.User.Identity.Name).IsAuthenticated)
        {
            return false;
        }

        return true;
    }

    protected override void HandleUnauthorizedRequest(AuthorizationContext    filterContext)
    {
        base.HandleUnauthorizedRequest(filterContext);

     }

}

then on your action:

然后你的行动:

[CustomAuthorizeAttribute(Roles = "FE")]
public ActionResult Index()
{
    return RedirectToAction("Index", "Documents");
}

however its still a string that you use and for it to work you need to combine it with Custom Role provider. Much hussle but worth it in my opinion.

但是它仍然是您使用的字符串,并且要使其工作,您需要将其与自定义角色提供程序结合使用。很麻烦,但在我看来值得。