2015-02-12 19 views
12

Sto tentando di creare un'API Web che consenta ai client dell'API (app mobili native) di accedere utilizzando un provider di archiviazione cloud di terze parti. Sto utilizzando il seguente flusso generale di Microsoft:Accesso OWIN/OAuth2 di terze parti: autenticazione dall'app client, autorizzazione da Web API

Ecco quello che sto cercando di realizzare:

Sto usando il default ASP.NET Web API Visual Studio modello con autenticazione esterna, insieme al pacchetto Nuget OWin.Security.Providers per la funzionalità di accesso a Dropbox e alle funzionalità di accesso integrate esistenti per Google (Drive) e Microsoft (OneDrive).

Il problema che sto avendo è che la funzionalità integrata sembra fare l'autenticazione e l'autorizzazione come parte di un flusso. Per esempio, se ho impostato il seguente in Startup.Auth.cs:

DropboxAuthenticationOptions dropboxAuthOptions = new DropboxAuthenticationOptions 
                { 
                 AppKey = _dropboxAppKey, 
                 AppSecret = _dropboxAppSecret 
                }; 
app.UseDropboxAuthentication(dropboxAuthOptions); 

... e passare a questo URL dal mio browser web:

http://<api_base_url>/api/Account/ExternalLogin?provider=Dropbox&response_type=token&client_id=self&redirect_uri=<api_base_url> 

sto reindirizzato con successo a Dropbox per login:

https://www.dropbox.com/1/oauth2/authorize?response_type=code&client_id=<id>&redirect_uri=<redirect_uri> 

... e poi dopo mi concedo l'accesso, sto reindirizzato a:

http://<api_base_url>/Help#access_token=<access_token>&token_type=bearer&expires_in=1209600 

... come si può vedere il token è parte di questo, quindi potrebbe essere estratto. Il problema è che il client deve essere quello che sta navigando su Dropbox e restituire il codice di autorizzazione all'API Web e l'API Web invierà il codice di autorizzazione alla terza parte per ottenere il token che verrà quindi restituito a il client ... come mostrato nello schema sopra. Ho bisogno l'azione ExternalLogin nel AccountController per recuperare in qualche modo l'url Dropbox e tornare che al cliente (che sarebbe solo una risposta JSON), ma non vedo un modo per recuperare che (solo restituisce un ChallengeResult, e la l'effettivo URL di Dropbox è sepolto da qualche parte). Inoltre, penso di aver bisogno di un modo per richiedere separatamente il token dai terzi in base al codice di autorizzazione.

Questo post sembra un po 'simile a quello che sto cercando di fare:

Registering Web API 2 external logins from multiple API clients with OWIN Identity

... ma la soluzione non sembra richiedere al cliente di essere un'applicazione MVC, che non è necessariamente il caso per me. Voglio mantenere questo il più semplice possibile dal lato client, seguire il flusso dal mio diagramma sopra, ma anche non reinventare la ruota (riutilizzare il più possibile di ciò che esiste già nell'implementazione OWIN/OAuth2). Idealmente non voglio che il client debba fare riferimento a nessuna delle librerie OWIN/OAuth poiché tutto ciò di cui ho veramente bisogno che il client faccia è accedere a un url esterno fornito dall'API (Dropbox nel mio esempio), chiedere all'utente di inserire le proprie credenziali e dare il permesso e inviare il codice di autorizzazione risultante di nuovo all'API.

Concettualmente questo non sembra così difficile, ma non ho idea di come implementarlo e utilizzare ancora il più possibile il codice OAuth esistente. Per favore aiuto!

risposta

4

Per essere chiari, l'esempio che ho citato nel link che hai postato PU CAN essere utilizzato con qualsiasi client OAuth2, utilizzando qualsiasi flusso supportato (implicito, codice o personalizzato).Quando comunichi con il tuo server di autorizzazione, puoi ovviamente utilizzare il flusso implicito se desideri utilizzare JS o app mobili: devi solo creare una richiesta di autorizzazione usando response_type=token ed estrarre il token di accesso dal frammento URI sul lato JS.

http://localhost:55985/connect/authorize?client_id=myClient&redirect_uri=http%3a%2f%2flocalhost%3a56854%2f&response_type=token

Per riferimento, ecco l'esempio: https://github.com/aspnet-security/AspNet.Security.OpenIdConnect.Server/tree/dev/samples/Mvc/Mvc.Server


Nel caso in cui si preferisce un approccio più semplice (che comporterebbe nessun server di autorizzazione OAuth2 personalizzato), ecco un'altra opzione utilizzando il middleware di autenticazione del portatore OAuth2 e l'implementazione di un custom IAuthenticationTokenProvider per validare manualmente il token opaco emesso da Dropbox. A differenza del campione citato (che funge da server proxy di autorizzazione tra Dropbox e l'app client MVC), l'app JS viene registrata direttamente con Dropbox.

È necessario effettuare una richiesta contro l'endpoint del profilo Dropbox (https://api.dropbox.com/1/account/info) con il token ricevuto per convalidarlo e creare un'istanza adeguata ClaimsIdentity per ogni richiesta ricevuta dall'API. Ecco un esempio (ma per favore non usarlo come-si, non è stato testato):

public sealed class DropboxAccessTokenProvider : AuthenticationTokenProvider { 
    public override async Task ReceiveAsync(AuthenticationTokenReceiveContext context) { 
     using (var client = new HttpClient()) { 
      var request = new HttpRequestMessage(HttpMethod.Get, "https://api.dropbox.com/1/account/info"); 
      request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", context.Token); 

      var response = await client.SendAsync(request); 
      if (response.StatusCode != HttpStatusCode.OK) { 
       return; 
      } 

      var payload = JObject.Parse(await response.Content.ReadAsStringAsync()); 

      var identity = new ClaimsIdentity("Dropbox"); 
      identity.AddClaim(new Claim(ClaimTypes.NameIdentifier, payload.Value<string>("uid"))); 

      context.SetTicket(new AuthenticationTicket(identity, new AuthenticationProperties())); 
     } 
    } 
} 

Si può facilmente collegarlo tramite la AccessTokenProvider proprietà:

app.UseOAuthBearerAuthentication(new OAuthBearerAuthenticationOptions { 
    AccessTokenProvider = new DropboxAccessTokenProvider() 
}); 

Essa ha la sua propri aspetti negativi: richiede il caching per evitare di inondare l'endpoint Dropbox e non è la strada giusta da percorrere se si desidera accettare token emessi da provider diversi (ad es. Dropbox, Microsoft, Google, Facebook).

Senza contare che se offre un livello di sicurezza molto basso : poiché non è possibile verificare il pubblico del token di accesso (ovvero la parte a cui è stato rilasciato il token), non è possibile garantire il token di accesso è stato rilasciato su un'applicazione client di cui ti fidi completamente, che consente a qualsiasi sviluppatore di terze parti di utilizzare i propri token Dropbox con la tua API senza dover richiedere il consenso dell'utente.

Questo è - ovviamente - un problema di sicurezza importante ed è per questo che DOVREBBE preferire l'approccio utilizzato nell'esempio collegato. Puoi leggere ulteriori informazioni sugli attacchi di delegati confusi su questo thread: https://stackoverflow.com/a/17439317/542757.

Buona fortuna, e non esitare se hai ancora bisogno di aiuto.

+0

Grazie per il vostro aiuto! Mi dispiace, sono un po 'nuovo per OAuth e sono ancora confuso. In che modo questo separa le parti di autenticazione e autorizzazione? Cioè, le 2 parti di cui ho bisogno sono: 1) Dato un nome del fornitore (stringa) passato dal client, come dovrei restituire l'url di autenticazione al client? ... e 2) Dato un codice di autorizzazione che il client passa all'api, come posso inviarlo insieme al codice OAuth integrato per completare l'autorizzazione e recuperare un token? – mayabelle

+0

Penso che la tua risposta copra come gestire le chiamate successive dopo che il client ha già il token e ha inviato il token all'api per eseguire un'operazione. Questo è molto utile in quanto sarebbe il mio prossimo passo. Ma in questo momento sono bloccato nella parte precedente, il flusso per ottenere il token al client in primo luogo (il client invia il nome del provider ad api, api restituisce l'URL di dropbox, il client passa all'URL di dropbox dove l'utente inserisce le credenziali e ottiene indietro codice di autorizzazione, il client invia il codice di autenticazione all'api, l'api chiama dropbox per scambiare il codice per un token, api restituisce token al client). – mayabelle

+0

Ok, grazie per il chiarimento. Come sarebbe questo se avessi bisogno di usare il flusso del codice? Sarebbe l'opzione 2?Se è così, com'è? – mayabelle

Problemi correlati