简体   繁体   中英

C# Attributes : Using enum constants as input parameters

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.

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

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 )

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.

the RequirePermission attribute defined as below :

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.

Any suggestion/idea is appreciated

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 :

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);
    }
}

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:

    [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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM