2013-10-28 9 views
7

Meine WebAPI 2-Anwendung verfügt über einen benutzerdefinierten Autorisierungsfilter, der nach einem Zugriffstoken sucht. Wenn das Token vorhanden ist und die API das Attribut besitzt, überprüfe ich, ob ein Benutzer existiert, der diesem Token zugeordnet ist.Festlegen des Prinzipal-/Benutzerkontexts für ein Benutzerobjekt

Aufgrund der Art der API werden die meisten Methoden im Kontext eines bestimmten Benutzers ausgeführt (d. H. "POST api/profile" zum Aktualisieren eines Benutzerprofils). Um dies zu tun, brauche ich Informationen über den Zielbenutzer, die ich vom Zugriffstoken bekomme.

[aktuelle Implementierung, geschieht innerhalb Attribute vom Typ AuthorizeAttribute]

if(myDBContext.MyUsers.Count(x => x.TheAccessToken == clientProvidedToken)){ 
    IPrincipal principal = new GenericPrincipal(new GenericIdentity(myAccessToken), new string[] { "myRole" }); 
    Thread.CurrentPrincipal = principal; 
    HttpContext.Current.User = principal; 
    return true; 
} 

Dies funktioniert gut, und ich bin in der Lage, um dann die Zugriffstoken zu verwenden, um eine zweite Suche in der Methode zu tun. Da ich aber zur Auth-Zeit schon einen Lookup mache, möchte ich keinen weiteren DB-Call verschwenden.

[Was ich tun möchte (aber offensichtlich nicht funktioniert)]

MyUser user = myDBContext.MyUsers.FirstOrDefault(x => x.TheAccessToken == clientProvidedToken); 
if(user != null){ 
    // Set *SOME* property to the User object, such that it can be 
    // access in the body of my controller method 
    // (e.g. /api/profile uses this object to load data) 
    HttpContext.Current.User = user; 
    return true; 
} 

Antwort

8

Sie können Ihre eigene Hauptklasse verwenden. Vielleicht so etwas wie:

public class MyPrincipal : GenericPrincipal 
{ 
    public MyPrincipal(IIdentity identity, string[] roles) 
     : base(identity, roles) 
    { 
    } 
    public MyUser UserDetails {get; set;} 
} 

Dann könnte Ihr Action-Filter tun:

MyUser user = myDBContext.MyUsers.FirstOrDefault(x => x.TheAccessToken == clientProvidedToken); 
if(user != null) 
{ 
    MyPrincipal principal = new MyPrincipal(new GenericIdentity(myAccessToken), new string[] { "myRole" }); 
    principal.UserDetails = user; 
    Thread.CurrentPrincipal = principal; 
    HttpContext.Current.User = principal; 
    return true; 
} 
return false; 

Und anschließend in Ihrer aktuellen Methode können Sie den aktuellen Benutzer nehmen, prüfen Sie, ob es vom Typ ist MyPrincipal und wenn es so gegossen und dann die Userdetails zugreifen:

... 
MyUser currentUser = null; 
MyPrincipal curPrincipal = HttpContext.Current.User as MyPrincipal; 
if (curPrincipal != null) 
{ 
    currentUser = curPrincipal.UserDetails; 
} 
... 

ich habe nicht actaully diesen Code versucht, so könnte es sein, Tippfehler ...

+0

Ich weiß nicht, warum ich nicht über die Erweiterung der GenericPrincipal - es dachte hat gut funktioniert! Vielen Dank! – ShaneC

7

Sie könnten einen ClaimsIdentity/ClaimsPrincipal verwenden und fügen Sie die Claims Sie später in Ihrem Controller benötigen, beispielsweise die Schauspieler ID oder andere Werte, die Sie benötigen.

Ich habe ein Beispiel gemacht, das Ansprüche an den Actor stellt, aber wenn es Ihnen besser passt, könnten Sie auch bei Claims direkt an den aktuellen User gelangen.

var identity = new ClaimsIdentity(HttpContext.Current.User.Identity); 
identity.Actor = new ClaimsIdentity(); 
identity.Actor.AddClaim(new Claim("Your", "Values")); 

var principal = new ClaimsPrincipal(identity); 
Thread.CurrentPrincipal = principal; 
HttpContext.Current.User = Thread.CurrentPrincipal; 
+1

Die Verwendung von Ansprüchen ist besser, weil sie eher mit dem Framework als mit dem Framework zusammenarbeitet. Oder wenn Code von HttpContext abhängig ist, könnte auch HttpContext.Profile verwendet werden. http://msdn.microsoft.com/en-us/library/system.web.httpcontext.profile(v=vs.110).aspx – user3285954

Verwandte Themen