Атрибуты C#: использование констант перечисления в качестве входных параметров

Я пытаюсь внедрить новый подход к доступу на основе разрешений для моего приложения MVC; У нас есть несколько групп разрешений, и каждая группа содержит список разрешений. например, у нас есть группа разрешений Invoices, которая содержит ключи разрешений CreateInvoice,RemoveInvoice,etc.

В этом подходе каждый mvc Action должен требовать определенного разрешения для выполнения. Я пытаюсь сделать это через CustomAttributes, что-то вроде этого:

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

Чтобы облегчить разработчикам запоминание различных групп разрешений и ключей разрешений, я пытаюсь создать предварительно определенный список разрешений, который должен представлять собой комбинацию группы разрешений и ключа разрешений. но из-за ограничений, применяемых к использованию аргументов атрибутов в С#, я пока не мог заставить его работать. (Я не хочу делать слишком большой счетчик и помещать туда все ключи разрешений)

моей последней попыткой было создать перечислитель для каждой группы разрешений, а затем определить ключи разрешений как константы перечисления:

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

Как видите, здесь у нас есть комбинация кодов: ключ группы разрешений, указанный с помощью атрибута PermissionGroup, и код ключа разрешений, указанный в виде числового кода для каждой константы перечисления.

атрибут RequirePermission, определенный ниже:

public class RequirePermissionAttribute : Attribute
{
    private Enum _Permission;

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

но проблема в том, что объекты типа Enum нельзя было использовать в качестве аргументов атрибутов.

Любое предложение/идея приветствуется


person Alireza Sabouri    schedule 17.09.2012    source источник


Ответы (2)


Я нашел решение, единственное, что нужно изменить, это тип параметра конструкции. вместо использования Enum вы должны использовать object :

public class RequirePermissionAttribute : AuthorizeAttribute
{
    private object _Permission;

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

Вот полный код:

/***************** 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);
    }
}
person Alireza Sabouri    schedule 18.09.2012

Я не думаю, что это возможно, я пытался сделать то, что вы делаете, и потерпел неудачу :/ извините.

Разрешения на действия следует использовать с Authorize, и вы можете сделать свою собственную оввериду, написав что-то вроде этого:

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

     }

}

затем в вашем действии:

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

однако это все еще строка, которую вы используете, и для ее работы вам необходимо объединить ее с поставщиком настраиваемых ролей. Много шума, но оно того стоит, на мой взгляд.

person AdrianCogiel    schedule 18.09.2012
comment
да, я сделал это, но моя проблема не в создании атрибута (атрибут ActionFilter) для проверки разрешений пользователя. Мне просто нужен лучший способ (чем использование простых строковых ключей) для создания предопределенных констант разрешений. - person Alireza Sabouri; 18.09.2012
comment
vivienchevallier.com/Articles/ Попробуйте это. - person AdrianCogiel; 19.09.2012