Вопрос по c#, custom-attributes – Как вставить параметры метода в пользовательский атрибут

13

У меня есть собственный атрибут с именем AuthoriseAttribute, конструктор которого выглядит следующим образом:

<code>public AuthoriseAttribute(int userId)
{
  .. blah
}
</code>

Это используется с методом под названиемGetUserDetails() как это:

<code>[Authorise(????????)]
public UserDetailsDto GetUserDetails(int userId)
{
  .. blah
}
</code>

Во время выполнения наличие атрибута Authorize приводит к выполнению некоторого кода авторизации, для которого требуется идентификатор пользователя. Очевидно, это можно извлечь из параметраGetUserDetails() метода, но это означает, что код авторизации зависит от параметра метода, которому присваивается конкретное имя.

Я хотел бы быть в состоянии передать фактическое значениеuserId параметр в атрибут, чтобы код авторизации работал со значением, переданным атрибуту (то есть не параметру метода), имя которого известно.

Примерно так (что не работает):

<code>[Authorise(userId)]
public UserDetailsDto GetUserDetails(int userId)
{
  .. blah
}
</code>

Это возможно?

Вместо того, чтобы передавать информацию о пользователях в каждый метод, вы могли бы получить свой атрибут другим способом, например, из контекста WCF или из Active Directory ... Тогда ваши методы чисты и не несут множественных обязанностей. Bob Horn
Есть кое-что, чего я не понимаю - зачем вам авторизовать параметр метода? ИМО - вам может потребоваться авторизовать вызывающего метода - это правильно? Sunny
То, что вы описываете, не может быть сделано напрямую, так как я уверен, что ошибка компилятора сказала вам. Было бы полезно узнать, как «наличие атрибута Authorize приводит к выполнению некоторого кода авторизации». работает. Вы должны быть в состоянии видеть код там в параметре userId. Tim S.
Нет не возможно. Атрибуты являются метаданными. Значения параметров должны быть постоянными. vcsjones
Спасибо, парни. @Tim: Я использую перехват Castle Castle Windsor. Наличие атрибута вызывает перехват вызова метода и позволяет мне запускать код перед вызовом. У меня есть доступ к информации о методе и информации об атрибутах. Мне нужно получить идентификатор пользователя (и другие вещи, но я упрощаю вопрос), но нет простого способа сообщить перехватчику, где найти идентификатор пользователя. Он может быть передан методу в виде параметра intuserIdили это может быть скрыто глубоко в каком-то параметре сложного типа. David

Ваш Ответ

3   ответа
16

Тамis способ сделать это_in ASP.NET MVC_ с методами действия (не с атрибутами вообще)

public class CustomAttribute : ActionFilterAttribute
{
    public override void OnActionExecuting(ActionExecutingContext filterContext)
    {
        int userId = (int)filterContext.ActionParameters["userId"];
    }
}
это работает нормально, спасибо!
15

Создание vcsjones & apos; комментировать ответ, это невозможно.

Атрибуты являются метаданными; они компилируются в сборку во время компиляции и не изменяются во время выполнения. Таким образом, любые параметры, которые вы передаете в атрибут, должны быть константами; литералы, постоянные переменные, определения компилятора и т. д.

Единственный способ, которым это сработало бы, - сделать атрибут элементом AOP, используя такую среду, как PostSharp, или развернуть собственную с помощью Unity Framework и т. Д. Это позволит вам присоединить & quot; перехватчик & quot; к методу, украсив его атрибутом, который затем запустит код в атрибуте, а также будет знать, как именно был вызван метод, включая значения параметров. Проверьте этот блог:http://www.progware.org/Blog/post/Interception-and-Interceptors-in-C-(Aspect-oriented-programming).aspx

+1 за хороший спорт. David
Я бы не сказал, что это воровство. +1 за то, что взял мой комментарий и превратил его в полезный ответ.
Вы "украли vcsjones" ответь и я тебя за это награжу! У меня есть AOP и работает; Моя проблема состоит в том, чтобы сообщить коду в перехватчике, где найти данные, необходимые для запуска логики авторизации, поскольку этот атрибут можно использовать для украшения нескольких методов с разными сигнатурами. David
Спасибо. Да, я думал об этом. Я не уверен, как заставить это работать, если параметр является сложным типом. Я должен был бы определить некоторый магический синтаксис для выражения местоположения требуемых данных в виде строки. Нужно подумать об этом. David
Вы, вероятно, дадите ему эту информацию, указав имя параметра, который будете использовать в качестве строки:[Authorize("userId")], Когда перехватчик, который вы определили, запускается, он должен иметь возможность проверять метаданные о вызове метода, который был сделан для его запуска, и должен иметь возможность найти параметр с указанным именем и присвоить его значение любому коду, который должен выполняться на основе этого приписывать.
0

Я смог обойти это с помощью следующего:

public class AuthorizeAttribute
{
    protected bool RequireIdClaim { get; private set; }

    public AuthorizeAttribute(bool requireIdClaim = false)
    {
        RequireIdClaim = requireIdClaim;
    }

    public Authorize() 
    {
        //regular auth stuff here

        if (RequireIdClaim)
        {
            var routeData = context.ActionContext.Request.GetRouteData();
            var requiredIdClaim = Convert.ToInt32(routeData.Values["id"]); 

            //Check here if their user profile has a claim to that Id
        }
    }
}

А затем о конкретных методах, которые вы хотите проверить идентификаторы,

[HttpGet]
[Route("{id}")]
[Authorize(requireIdClaim: true)]
public UserDetailsDto GetUserDetails(int userId)
{
    .. blah
}

И если вы не хотите проверять их Id, а только то, что они аутентифицированы

[HttpGet]
[Route("")]
[Authorize]
public bool isLoggedIn()
{
    .. blah
}

Конечно, вы можете организовать свою процедуру авторизации, как вам нравится, но эта идея позволяет вам получить их ID в вашей процедуре авторизации, поскольку она передается в качестве данных маршрута. Больше здесь:https://stackoverflow.com/a/16054886

Похожие вопросы