Ottieni IPrincipal dal token bearer OAuth in OWIN

Ho aggiunto OAuth al mio progetto WebAPI 2 con OWIN. Ricevo token e posso usarli nell’intestazione HTTP per accedere alle risorse.

Ora voglio usare quei token anche su altri canali per l’autenticazione che non sono le richieste HTTP standard per cui è fatto il modello OWIN. Ad esempio, sto utilizzando WebSockets in cui il client deve inviare il token bearer OAuth per l’autenticazione.

Sul lato server, ricevo il token tramite WebSocket. Ma come posso ora mettere questo token nella pipeline OWIN per estrarre IPrincipal e ClientIdentifier da esso? Nel modello WebApi 2 tutto ciò è astratto per me, quindi non c’è nulla che io debba fare per farlo funzionare.

Quindi, fondamentalmente, ho il token come stringa e voglio usare OWIN per accedere alle informazioni utente codificate in quel token.

Grazie in anticipo per l’aiuto.

Ho trovato una parte della soluzione in questo post del blog: http://leastprivilege.com/2013/10/31/retrieving-bearer-tokens-from-alternative-locations-in-katanaowin/

Così ho creato il mio provider come segue:

public class QueryStringOAuthBearerProvider : OAuthBearerAuthenticationProvider { public override Task RequestToken(OAuthRequestTokenContext context) { var value = context.Request.Query.Get("access_token"); if (!string.IsNullOrEmpty(value)) { context.Token = value; } return Task.FromResult(null); } } 

Quindi ho dovuto aggiungerlo alla mia app in Startup.Auth.cs in questo modo:

 OAuthBearerOptions = new OAuthBearerAuthenticationOptions() { Provider = new QueryStringOAuthBearerProvider(), AccessTokenProvider = new AuthenticationTokenProvider() { OnCreate = create, OnReceive = receive }, }; app.UseOAuthBearerAuthentication(OAuthBearerOptions); 

Con un AuthenticationTokenProvider personalizzato, posso recuperare tutti gli altri valori dal token all’inizio della pipeline:

 public static Action create = new Action(c => { c.SetToken(c.SerializeTicket()); }); public static Action receive = new Action(c => { c.DeserializeTicket(c.Token); c.OwinContext.Environment["Properties"] = c.Ticket.Properties; }); 

E ora, per esempio nel mio WebSocket Hander, posso recuperare ClientId e altri come questo:

 IOwinContext owinContext = context.GetOwinContext(); if (owinContext.Environment.ContainsKey("Properties")) { AuthenticationProperties properties = owinContext.Environment["Properties"] as AuthenticationProperties; string clientId = properties.Dictionary["clientId"]; ... } 

Per impostazione predefinita, OWIN utilizza la protezione dei dati della chiave della macchina ASP.NET per proteggere il token di accesso OAuth quando è ospitato su IIS. È ansible utilizzare la class MachineKey in System.Web.dll per rimuovere la protezione dai token.

 public class MachineKeyProtector : IDataProtector { private readonly string[] _purpose = { typeof(OAuthAuthorizationServerMiddleware).Namespace, "Access_Token", "v1" }; public byte[] Protect(byte[] userData) { throw new NotImplementedException(); } public byte[] Unprotect(byte[] protectedData) { return System.Web.Security.MachineKey.Unprotect(protectedData, _purpose); } } 

Quindi, creare un TicketDataFormat per ottenere l’object AuthenticationTicket in cui è ansible ottenere ClaimsIdentity e AuthenticationProperties.

 var access_token="your token here"; var secureDataFormat = new TicketDataFormat(new MachineKeyProtector()); AuthenticationTicket ticket = secureDataFormat.Unprotect(access_token); 

Per rimuovere la protezione di altri token OAuth, è sufficiente modificare il contenuto _purpose. Per informazioni dettagliate, vedere la class OAuthAuthorizationServerMiddleware qui: http://katanaproject.codeplex.com/SourceControl/latest#src/Microsoft.Owin.Security.OAuth/OAuthAuthorizationServerMiddleware.cs

 if (Options.AuthorizationCodeFormat == null) { IDataProtector dataProtecter = app.CreateDataProtector( typeof(OAuthAuthorizationServerMiddleware).FullName, "Authentication_Code", "v1"); Options.AuthorizationCodeFormat = new TicketDataFormat(dataProtecter); } if (Options.AccessTokenFormat == null) { IDataProtector dataProtecter = app.CreateDataProtector( typeof(OAuthAuthorizationServerMiddleware).Namespace, "Access_Token", "v1"); Options.AccessTokenFormat = new TicketDataFormat(dataProtecter); } if (Options.RefreshTokenFormat == null) { IDataProtector dataProtecter = app.CreateDataProtector( typeof(OAuthAuthorizationServerMiddleware).Namespace, "Refresh_Token", "v1"); Options.RefreshTokenFormat = new TicketDataFormat(dataProtecter); } 

oltre alla risposta johnny-qian , utilizzando questo metodo è preferibile creare DataProtector. Risposta johnny-qian , dipende da IIS e non riesce su scenari auto-ospitati.

 using Microsoft.Owin.Security.DataProtection; var dataProtector = app.CreateDataProtector(new string[] { typeof(OAuthAuthorizationServerMiddleware).Namespace, "Access_Token", "v1" }); 

Com’è il tuo token, è una stringa di crittografia o una stringa formattata, qual è il formato?

Io il mio codice:

 public static Action receive = new Action(c => { if (!string.IsNullOrEmpty(c.Token)) { c.DeserializeTicket(c.Token); //c.OwinContext.Environment["Properties"] = c.Ticket.Properties; } }); 

Il c.Ticket è sempre nullo.