2012-05-03 5 views
9

Ich habe ein benutzerdefiniertes Attribut AuthoriseAttribute dessen Konstruktor sieht wie folgt genannt:Wie Methodenparameter in benutzerdefinierte Attribute stopfen

public AuthoriseAttribute(int userId) 
{ 
    .. blah 
} 

Dieses mit einem Verfahren GetUserDetails() wie folgt aufgerufen verwendet wird:

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

Bei Zur Laufzeit führt das Vorhandensein des Autorize-Attributs zur Ausführung eines Autorisierungscodes, der die ID des Benutzers erfordert. Offensichtlich kann dies aus dem Parameter der GetUserDetails()-Methode extrahiert werden, aber das bedeutet, dass der Autorisierungscode davon abhängt, dass der Parameter der Methode einen bestimmten Namen erhält.

Ich möchte in der Lage sein, den tatsächlichen Wert des userId Parameters in das Attribut zu übergeben, damit der Autorisierungscode mit dem an das Attribut übergebenen Wert arbeitet (dh nicht der Methodenparameter), dessen Name bekannt ist .

So etwas (was nicht funktioniert):

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

Ist so etwas möglich?

+5

Nein nicht möglich. Attribute sind Metadaten. Parameterwerte müssen ein konstanter Wert sein. – vcsjones

+0

Es gibt etwas, das ich nicht verstehe - warum möchten Sie einen Methodenparameter autorisieren?IMO - Sie müssen möglicherweise den Aufrufer der Methode autorisieren - ist das korrekt? – Sunny

+2

Was Sie beschreiben, kann nicht direkt erledigt werden, da ich sicher bin, dass Ihnen der Compilerfehler mitgeteilt wurde. Es wäre hilfreich zu wissen, wie "das Vorhandensein des Authorize-Attributs dazu führt, dass ein Autorisierungscode ausgeführt wird". Sie sollten in der Lage sein, den Code dort auf den userId-Parameter zu haben. –

Antwort

12

Wenn Sie den Kommentar von vcsjones zu einer Antwort machen, ist dies nicht möglich.

Attribute sind Metadaten; Sie werden zur Kompilierungszeit in die Assembly kompiliert und ändern sich zur Laufzeit nicht. Daher müssen alle Parameter, die Sie an ein Attribut übergeben, Konstanten sein. Literale, Konstantenvariablen, Compilerdefinitionen, usw.

Die eine Möglichkeit wäre, das Attribut zu einem AOP-Element zu machen, ein Framework wie PostSharp zu verwenden oder eigene mit dem Unity Framework usw. zu rollen ein "Interzeptor" für die Methode, indem sie mit einem Attribut versehen wird, das dann Code in dem Attribut ausführt und auch Kenntnisse darüber hat, wie genau die Methode aufgerufen wurde, einschließlich Parameterwerte. Schauen Sie sich dieses Blog: http://www.progware.org/Blog/post/Interception-and-Interceptors-in-C-(Aspect-oriented-programming).aspx

+0

Sie haben vcsjones Antwort gestohlen und ich werde Sie dafür belohnen! Ich habe das AOP-Zeug in der Hand. Mein Problem besteht darin, dem Code im Interceptor mitzuteilen, wo die Daten zu finden sind, die er zum Ausführen der Berechtigungslogik benötigt, da das Attribut dazu verwendet werden kann, mehrere Methoden mit unterschiedlichen Signaturen zu dekorieren. – David

+7

Ich würde nicht sagen, dass es stehlen ist. +1, um meinen Kommentar zu nehmen und ihn zu einer nützlichen Antwort zu machen. – vcsjones

+0

+1 für einen guten Sport. – David

14

Es ist eine Möglichkeit, dies _in ASP.NET MVC_ mit Action-Methoden (nicht mit Attributen im Allgemeinen) zu tun

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

das funktioniert gut, danke! –

0

konnte ich dieses Problem umgehen, indem Sie den folgenden:

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

Und dann auf die spezifischen Methoden, die Sie auf überprüfen Ids wollen,

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

Und wenn Sie kümmern sich nicht ihre Id zu überprüfen, aber nur, dass sie authentifiziert sind

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

Natürlich können Sie Ihre authorise Verfahren organisieren, wie Sie wollen, aber diese Idee ermöglicht es Ihnen, Holen Sie ihre ID in Ihre Auth-Prozedur, da sie als Routendaten übergeben wird. Mehr hier: https://stackoverflow.com/a/16054886