2016-04-20 26 views
16

Sto scrivendo un'applicazione con un front end in emberjs e backend/server-side in un server nodejs. Ho emberjs configurato in modo che un utente possa accedere/registrarsi con un Oauth di terze parti (google, twitter, Facebook). Ho un back-end scritto nel server expressjs che ospita le API RESTful.Strategia token JWT per frontend e backend

Non ho il DB connesso a emberjs e non penso che dovrei comunque poiché è strettamente codice lato client. Sto pianificando di utilizzare JWT per comunicare tra lato client e lato server. Quando un utente accede con il proprio cred di oauth, ottengo un oggetto JSON dal provider con uid, nome, login, access_token e altri dettagli.

Sto lottando con la scelta di una strategia su come gestire la registrazione dell'utente. Non esiste un processo di iscrizione poiché è OAuth. Quindi il flusso è se l'utente non è nel mio db, crealo. Non supporto l'autenticazione email/password. Quale sarebbe il flusso quando un utente accede per la prima volta a un provider OAuth? Gli emberjs dovrebbero inviare tutti i dettagli al back-end ad ogni accesso in modo che il back-end possa aggiungere nuovi utenti al db?

Cosa dovrebbe fare parte del mio corpo JWT? Stavo pensando che uid e fornitore hanno fornito un token di accesso. Un problema a cui posso pensare è che il token di accesso specifico del provider può cambiare. L'utente può revocare il token dal sito del provider e registrarsi di nuovo con emberjs.

Sono aperto a scrivere il front-end in qualsiasi altro framework lato client javascript se rende più semplice.

+0

Sei dopo una descrizione su come farlo o tutto il codice? Nota, ember e node sono perfettamente adatti per questo, lo stack tecnologico per client e backend non dovrebbe fare alcuna differenza sostanziale per la soluzione. – Harry

+0

Sto cercando un flusso di processo su come i vari componenti dovrebbero comunicare in quale fase. Non ho bisogno del codice – ed1t

risposta

14

Se stiamo parlando non solo di lavoro, ma anche garantire l'autenticazione senza stato dovrai prendere in considerazione una strategia appropriata con entrambi i token access e refresh.

  1. token di accesso è un token che fornisce un accesso ad una risorsa protetta. Expiration qui potrebbe essere installato approssimativamente in ~ 1 ora (dipende dalle vostre considerazioni).

  2. token di aggiornamento è un token speciale che dovrebbe essere utilizzato per generare ulteriori access token nel caso in cui si è scaduto o sessione utente è stato aggiornato. Ovviamente è necessario farlo durare a lungo (rispetto a access token) e proteggere il più possibile. Expiration qui può essere installato approssimativamente in ~ 10 giorni o anche più (dipende anche dalle vostre considerazioni).

FYI: Dal refresh tokens sono vissuto a lungo, per renderle davvero sicure si potrebbe desiderare di memorizzarli nel database (refresh richieste di token sono eseguite raramente). In questo modo, diciamo, anche se il tuo token di aggiornamento è stato violato in qualche modo e qualcuno ha rigenerato i token access/refresh, ovviamente perderai le autorizzazioni, ma puoi comunque accedere al sistema, poiché sai login/passaggio (nel caso utilizzi più tardi) o semplicemente accedendo tramite qualsiasi social network.


Dove memorizzare questi token?

Ci sono fondamentalmente 2 posti comuni:

  1. HTML5 Web bagagli (localStorage/sessionStorage)

bene ad andare, ma nello stesso tempo abbastanza rischioso. Lo spazio di archiviazione è accessibile tramite codice javascript nello stesso dominio. Ciò significa che se hai XSS, i tuoi token potrebbero essere violati. Quindi, scegliendo questo metodo, è necessario fare attenzione e codificare/sfuggire a tutti i dati non attendibili. E anche se lo facessi, sono abbastanza sicuro che tu usi alcuni moduli client-side di terze parti e non c'è alcuna garanzia che qualcuno di questi abbia un codice malevolo.

Anche Web Storage non applica alcun standard sicuro durante il trasferimento. Quindi devi assicurarti che JWT sia inviato oltre HTTPS e mai HTTP.

  1. Cookies

Con specifici HttpOnly cookie di opzione non sono accessibili tramite JavaScript e sono immuni da XSS. È inoltre possibile impostare il flag del cookie Secure per garantire che il cookie venga inviato solo tramite HTTPS. Tuttavia, i cookie sono vulnerabili a un diverso tipo di attacco: falsificazione di richieste tra siti (CSRF). In questo caso è possibile prevenire CSRF utilizzando alcuni tipi di token sincronizzati. Esiste una buona implementazione in AngularJS, nella sezione Security Considerations.

Un article si potrebbe voler seguire.

per illustrare come funziona in generale:

http://jlabusch.github.io/oauth2-server/img/diag_refresh_token.png


Poche parole su JWT stessa:

mettere in chiaro non v'è davvero cool JWT Debugger da ragazzi Auth0. Esistono 2 tipi di attestazioni comuni (a volte 3): public, private (e reserved).

Un esempio di JWT corpo (payload, può essere quello che vuoi):

{  
    name: "Dave Doe", 
    isAdmin: true, 
    providerToken: '...' // should be verified then separately 
} 

Maggiori informazioni su JWT struttura troverete here.

3

Per qualsiasi flusso di lavoro OAuth, è necessario utilizzare la libreria passportjs. Dovresti anche leggere la documentazione completa. È facile da capire, ma ho commesso l'errore di non leggere l'intera cosa la prima volta e ho faticato. Contiene l'autenticazione OAuth con oltre 300 provider e token di rilascio.

Tuttavia, se si vuole farlo manualmente o vuole una conoscenza di base, qui è il flusso che userei:

  1. Frontend ha una pagina di accesso messa in vendita di Sign-in con Google/Facebook etc dove è implementato OAuth.

  2. risultati OAuth di successo in un'UID, login, ecc access_token (oggetto JSON)

  3. si registra l'oggetto JSON per il percorso /login/ nell'applicazione Node.js. (Sì, si invia l'intera risposta, indipendentemente se si tratta di un utente nuovo o esistente. L'invio di dati aggiuntivi qui è meglio che non fare due richieste)

  4. L'applicazione di backend legge il uid e access_token. Assicurarsi che access_token sia valido seguendo (https://developers.facebook.com/docs/facebook-login/manually-build-a-login-flow#checktoken) o chiedendo i dati utente dal provider utilizzando il token di accesso. (Questo fallirà per un token di accesso non valido poiché i token di accesso OAuth sono generati su base app/sviluppatore) Ora, cerca il tuo DB di back-end.

  5. Se il uid esiste nel database, si aggiorna il token di accesso dell'utente e scadeIn nel DB. (Il token di accesso consente di ottenere maggiori informazioni da Facebook per quel particolare utente e di solito fornisce l'accesso per alcune ore.)

  6. Altrimenti, si crea un nuovo utente con uid, accesso, ecc informazioni.

  7. Dopo l'aggiornamento del token di accesso o la creazione di un nuovo utente, si invia token JWT contenente uid.(Codificare il JWT con un segreto, questo garantirebbe che è stato inviato da te e non sono stati manomessi. Checkout https://github.com/auth0/express-jwt)

  8. Sulla frontend dopo che l'utente ha ricevuto il JWT da /login, salvarlo sul sessionStorage da sessionStorage.setItem('jwt', token);

  9. Sul frontend, aggiungere anche la seguente:

if ($window.sessionStorage.token) { xhr.setRequestHeader("Authorization", $window.sessionStorage.token); }

Ciò all'e Supponiamo che se c'è un token jwt, viene inviato con ogni richiesta.

  1. su File tuoi Node.js app.js, aggiungere

app.use(jwt({ secret: 'shhhhhhared-secret'}).unless({path: ['/login']}));

Ciò convalidare che JWT per qualsiasi cosa nel tuo percorso, assicurando che l'utente è loggato, altrimenti non consentire l'accesso e il reindirizzamento alla pagina di accesso. Il caso di eccezione qui è /login poiché è lì che si fornisce a JWT sia gli utenti nuovi sia quelli non autenticati.

È possibile trovare ulteriori informazioni sull'URL Github su come ottenere il token e per scoprire quale richiesta dell'utente si sta attualmente servendo.

+0

Come proteggi il tuo/endpoint di accesso nel tuo back-end in modo che solo il lato client sia autorizzato a postare e non qualcuno? – ed1t

+0

Si utilizza CORS. Aggiungi 'Access-Control-Allow-Origin: http: // www.foo.com' sul tuo back-end in modo che solo" Origin: http: // www.foo.com' possa inviare dati POST a '/ login' –

+0

Codice per farlo: http://enable-cors.org/server_expressjs.html –

3

di rispondere alle due domande specifiche che si poneva:

Quale sarebbe il flusso quando un utente accede con un provider di OAuth per la prima volta? Gli emberjs dovrebbero inviare tutti i dettagli al back-end su ogni accesso in modo che il back-end possa aggiungere nuovi utenti al db?

Ogni volta che un utente o si iscrive o si connette tramite OAuth e il vostro cliente riceve un nuovo token di accesso indietro, lo farei upsert (aggiornare o inserire) nella tua tabella utenti (o raccolta) insieme a qualsiasi nuovo o informazioni aggiornate che hai recuperato sull'utente dall'API del provider oauth. Suggerisco di archiviarlo direttamente su ogni record degli utenti per garantire che il token di accesso e le informazioni del profilo associato cambino atomicamente. In generale, di solito lo compongo in una sorta di middleware che esegue automaticamente questi passaggi quando è presente un nuovo token.

Quale dovrebbe essere la parte del mio corpo JWT? Stavo pensando al token di accesso fornito da uid e provider . Un problema a cui posso pensare è che il token di accesso specifico del provider può cambiare. L'utente può revocare il token dal sito del fornitore e registrarsi di nuovo con emberjs.

Il corpo JWT generalmente costituito dai utenti sostiene. Personalmente vedo poco vantaggio nell'archiviazione del token di accesso al provider nel corpo di un token JWT poiché avrebbe alcuni vantaggi per l'app del client (a meno che non si stiano facendo molte chiamate API dirette dal proprio client alle proprie API, preferisco fare quelle chiamano lato server e inviano al mio client di app un insieme normalizzato di attestazioni che aderiscono alla mia stessa interfaccia). Scrivendo la tua interfaccia di reclamo, non dovrai aggirare le varie differenze presenti da più fornitori dall'app client.Un esempio di questo sarebbe coalizzare i campi specifici di Twitter e Facebook che sono denominati in modo diverso nelle loro API per i campi comuni che si archiviano sulla tabella del profilo utente, quindi incorporare i campi del profilo locale come attestazioni nel corpo JWT da interpretare dall'app client . Vi è un ulteriore vantaggio in questo, che non si potranno persistere dati che potrebbero perdere in futuro in un token JWT non crittografato.

Indipendentemente dal fatto che si stia memorizzando il token di accesso fornito dal provider oauth all'interno del corpo del token JWT, sarà necessario concedere un nuovo token JWT ogni volta che i dati del profilo cambiano (è possibile inserire un meccanismo per ignorare l'emissione di nuovi token JWT se nessun aggiornamento del profilo si è verificato e il token precedente è ancora buono).

Oltre a tutto ciò campi profilo si memorizzano come crediti nel corpo del token JWT, vorrei sempre definire lo standard di JWT token body fields:

{ 
    iss: "https://YOUR_NAMESPACE", 
    sub: "{connection}|{user_id}", 
    aud: "YOUR_CLIENT_ID", 
    exp: 1372674336, 
    iat: 1372638336 
} 
Problemi correlati