Cómo conectar parámetros de método en un atributo personalizado

Tengo un atributo personalizado llamado AuthoriseAttribute cuyo constructor se ve así:

public AuthoriseAttribute(int userId)
{
  .. blah
}

Esto se usa con un método llamado GetUserDetails() Me gusta esto:

[Authorise(????????)]
public UserDetailsDto GetUserDetails(int userId)
{
  .. blah
}

En tiempo de ejecución, la presencia del atributo Autorizar hace que se ejecute un código de autorización que requiere el ID del usuario. Obviamente, esto se puede extraer del parámetro de la GetUserDetails() método, pero esto significa que el código de autorización depende de que el parámetro del método reciba un nombre particular.

Me gustaría poder pasar el valor real de la userId parámetro en el atributo, de modo que el código de autorización funcione con el valor pasado al atributo (es decir, no el parámetro del método), cuyo nombre se conoce.

Algo como esto (que no funciona):

[Authorise(userId)]
public UserDetailsDto GetUserDetails(int userId)
{
  .. blah
}

¿Es posible tal cosa?

preguntado el 03 de mayo de 12 a las 17:05

No, no es posible. Los atributos son metadatos. Los valores de los parámetros deben ser un valor constante. -

Hay algo que no entiendo: ¿por qué querrías autorizar un parámetro de método? En mi opinión, es posible que deba autorizar a la persona que llama al método, ¿es correcto? -

Lo que describes no se puede hacer directamente, como estoy seguro de que te lo dijo el error del compilador. Sería útil saber cómo funciona "la presencia del atributo Autorizar hace que se ejecute algún código de autorización". Debería poder hacer que el código allí mire el parámetro ID de usuario. -

En lugar de pasar la información del usuario a cada método, puede hacer que su atributo lo obtenga por otros medios, como el contexto de WCF o desde Active Directory... Entonces sus métodos están limpios y no tienen múltiples responsabilidades. -

Gracias chicos. @Tim: Estoy usando la interceptación de Castle Windsor. La presencia del atributo hace que se intercepte la invocación del método y me permite ejecutar el código antes de la invocación. Tengo acceso a la información del método y la información del atributo. Necesito obtener la identificación del usuario (y otras cosas, pero mantengo la pregunta simple), pero no hay una manera simple de decirle al interceptor dónde encontrar la identificación del usuario. Podría pasarse al método como un parámetro int llamado userId, o podría estar enterrado profundamente en algún parámetro de tipo complejo. -

4 Respuestas

Aún así, is una forma de hacer esto _en ASP.NET MVC_ con métodos de acción (no con atributos en general)

public class CustomAttribute : ActionFilterAttribute
{
    public override void OnActionExecuting(ActionExecutingContext filterContext)
    {
        int userId = (int)filterContext.ActionParameters["userId"];
    }
}

Respondido el 05 de diciembre de 14 a las 22:12

Haciendo del comentario de vcsjones una respuesta, esto no es posible.

Los atributos son metadatos; se compilan en el ensamblado en tiempo de compilación y no cambian durante el tiempo de ejecución. Como tal, cualquier parámetro que pase a un atributo debe ser constante; literales, variables constantes, definiciones del compilador, etc.

La única forma en que esto funcionaría es hacer que el atributo sea un elemento AOP, usando un marco como PostSharp o implementando el suyo propio con Unity Framework, etc. Esto le permitiría adjuntar un "interceptor" al método decorándolo con un atributo, que luego ejecutará el código en el atributo y también tendrá conocimiento sobre cómo se llamó exactamente al método, incluidos los valores de los parámetros. Echa un vistazo a este blog: http://www.progware.org/Blog/post/Interception-and-Interceptors-in-C-(Aspect-oriented-programming).aspx

contestado el 03 de mayo de 12 a las 17:05

¡Has robado la respuesta de vcsjones y te recompensaré por ello! Tengo las cosas de AOP en funcionamiento; mi problema es decirle al código en el interceptor dónde encontrar los datos que necesita para ejecutar la lógica de autorización, ya que el atributo podría usarse para decorar varios métodos con diferentes firmas. - David

Yo no diría que es robar. +1 por tomar mi comentario y convertirlo en una respuesta útil. - vcsjones

Probablemente le daría esta información al darle el nombre del parámetro que usaría como una cadena: [Authorize("userId")]. Cuando el interceptor que definió se ejecuta, debería poder examinar los metadatos sobre la llamada al método que se realizó para activarlo, y debería poder encontrar el parámetro con el nombre especificado y dar su valor a cualquier código que deba ejecutarse en función de esto. atributo. - keiths

Gracias. Sí, pensé en eso. No estoy seguro de cómo haría que funcionara si el parámetro es de tipo complejo. Tendría que definir algún tipo de sintaxis mágica para expresar la ubicación de los datos requeridos como una cadena. Necesito pensar en esto. - David

Bueno, no querrías definir [Authorize("userId.SomeProp")]. Si necesita saber el tipo exacto del parámetro, también puede especificarlo: [Authorize("userId", typeof(MyComplexType))] - keiths

Pude solucionar esto usando lo siguiente:

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

Y luego, en los métodos específicos en los que desea verificar las identificaciones,

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

Y si no le importa verificar su identificación, sino solo que estén autenticados

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

Por supuesto, puede organizar su procedimiento de autorización como desee, pero esta idea le permite obtener su ID en su procedimiento de autenticación, ya que se transmite como datos de ruta. Más aquí: https://stackoverflow.com/a/16054886

Respondido 01 Feb 18, 13:02

Probablemente porque esta es una publicación anterior, pero ahora es posible

[MyAttribute(MyAttributeVar= "myMethodVar")]
public void MyMethod(int myMethodVar)

Respondido el 07 de diciembre de 20 a las 11:12

No es la respuesta que estás buscando? Examinar otras preguntas etiquetadas or haz tu propia pregunta.