Ci sono molte domande qui poste, e sembra che anche se le domande siano poste nel contesto di Node e passport.js, le vere domande riguardano più il flusso di lavoro che come farlo con una particolare tecnologia.
Usiamo l'impostazione di esempio @Keith, modificata un po 'per una maggiore sicurezza:
- Il server Web
https://example.com
serve un'app client Javascript a pagina singola
- Il servizio Web RESTful su
https://example.com/api
fornisce supporto server all'app rich client
- Server implementato in Node e passport.js.
- Il server ha un database (qualsiasi tipo) con una tabella "utenti".
- Nome utente / password e Facebook Connect sono offerti come opzioni di autenticazione
- Rich client effettua richieste REST in
https://example.com/api
- Potrebbero esserci altri client (app telefoniche, ad esempio) che utilizzano il servizio Web all'indirizzo
https://example.com/api
ma non conoscono il server Web all'indirizzo https://example.com
.
Nota che sto usando HTTP sicuro. Questo è secondo me un must per qualsiasi servizio disponibile all'aperto, poiché informazioni sensibili come password e token di autorizzazione passano tra client e server.
Autenticazione nome utente / password
Diamo un'occhiata a come funziona per prima la semplice autenticazione.
- L'utente si connette a
https://example.com
- Il server serve una ricca applicazione Javascript che rende la pagina iniziale. Da qualche parte nella pagina c'è un modulo di login.
- Molte sezioni di questa app a pagina singola non sono state popolate con dati a causa della mancata connessione dell'utente. Tutte queste sezioni hanno un listener di eventi su un evento "login". Tutto questo è roba lato client, il server non è a conoscenza di questi eventi.
- L'utente inserisce login e password e preme il pulsante di invio, che attiva un gestore Javascript per registrare il nome utente e la password nelle variabili lato client. Quindi questo gestore attiva l'evento "login". Ancora una volta, questa è tutta l'azione lato client, le credenziali non sono state ancora inviate al server .
- I listener dell'evento "login" vengono richiamati. Ognuno di questi ora deve inviare una o più richieste all'API RESTful su
https://example.com/api
per ottenere i dati specifici dell'utente da visualizzare sulla pagina. Ogni singola richiesta che inviano al servizio Web includerà il nome utente e la password, possibilmente sotto forma di autenticazione HTTP di base , poiché il servizio RESTful non è autorizzato a mantenere lo stato del client da una richiesta all'altra. Poiché il servizio Web è su HTTP sicuro, la password viene crittografata in modo sicuro durante il transito.
- Il servizio web all'indirizzo
https://example.com/api
riceve un sacco di richieste individuali, ognuna con informazioni di autenticazione. Il nome utente e la password in ciascuna richiesta vengono verificati rispetto al database utente e, se trovati corretti, viene eseguita la funzione richiesta e i dati vengono restituiti al client in formato JSON. Se nome utente e password non corrispondono, viene inviato un errore al client sotto forma di un codice di errore HTTP 401.
- Invece di forzare i client a inviare nome utente e password con ogni richiesta, puoi avere una funzione "get_access_token" nel tuo servizio RESTful che prende nome utente e password e risponde con un token, che è una sorta di hash crittografico che è unico e ha una scadenza data ad esso associata. Questi token sono archiviati nel database con ciascun utente. Quindi il client invia il token di accesso nelle richieste successive. Il token di accesso verrà quindi convalidato rispetto al database anziché al nome utente e alla password.
- Le applicazioni client non browser come le app telefoniche fanno le stesse delle precedenti, chiedono all'utente di inserire le proprie credenziali, quindi di inviarle (o un token di accesso generato da esse) con ogni richiesta al servizio web.
L'importante punto da togliere da questo esempio è che i servizi Web RESTful richiedono l'autenticazione con ogni richiesta .
Un ulteriore livello di sicurezza in questo scenario aggiungerebbe l'autorizzazione dell'applicazione client oltre all'autenticazione dell'utente. Ad esempio, se si dispone del client Web, delle app iOS e Android che utilizzano tutti il servizio Web, è possibile che il server sappia quale dei tre è il client di una determinata richiesta, indipendentemente da chi sia l'utente autenticato. Ciò può consentire al servizio Web di limitare determinate funzioni a client specifici. Per questo potresti usare chiavi API e segreti, vedi questa risposta per alcune idee a riguardo.
Autenticazione di Facebook
Il flusso di lavoro sopra non funziona per la connessione di Facebook perché l'accesso tramite Facebook ha una terza parte, Facebook stesso. La procedura di accesso richiede che l'utente venga reindirizzato al sito Web di Facebook in cui le credenziali vengono immesse al di fuori del nostro controllo.
Quindi vediamo come cambiano le cose :.
- L'utente si connette a
https://example.com
- Il server serve una ricca applicazione Javascript che rende la pagina iniziale. Nella pagina è presente un modulo di accesso che include un pulsante "Accedi con Facebook".
- L'utente fa clic sul pulsante "Accedi con Facebook", che è solo un link che reindirizza a (ad esempio)
https://example.com/auth/facebook
.
- Il
https://example.com/auth/facebook
percorso è gestito da passport.js (consultare la documentazione )
- Tutto ciò che l'utente vede è che la pagina cambia e ora si trovano in una pagina ospitata su Facebook dove devono accedere e autorizzare la nostra applicazione web. Questo è completamente al di fuori del nostro controllo.
- L'utente accede a Facebook e dà l'autorizzazione alla nostra applicazione, quindi Facebook ora reindirizza nuovamente all'URL di richiamata che abbiamo configurato nell'impostazione passport.js, che seguendo l'esempio nella documentazione è
https://example.com/auth/facebook/callback
- Il gestore passport.js per il
https://example.com/auth/facebook/callback
percorso richiamerà la funzione di richiamata che riceve il token di accesso a Facebook e alcune informazioni dell'utente da Facebook, incluso l'indirizzo e-mail dell'utente.
- Con l'e-mail possiamo individuare l'utente nel nostro database e archiviare il token di accesso di Facebook con esso.
- L'ultima cosa che fai nel callback di Facebook è il reindirizzamento all'applicazione rich client, ma questa volta dobbiamo passare il nome utente e il token di accesso al client in modo che possano utilizzarli. Questo può essere fatto in diversi modi. Ad esempio, le variabili Javascript possono essere aggiunte alla pagina tramite un motore modello lato server, oppure è possibile restituire un cookie con queste informazioni. (grazie a @RyanKimber per aver segnalato i problemi di sicurezza con il passaggio di questi dati nell'URL, come inizialmente suggerito).
- Quindi ora avviamo l'app a pagina singola ancora una volta, ma il client ha il nome utente e il token di accesso.
- L'applicazione client può attivare immediatamente l'evento "login" e lasciare che le diverse parti dell'applicazione richiedano le informazioni di cui hanno bisogno dal servizio web.
- Tutte le richieste inviate
https://example.com/api
includeranno il token di accesso di Facebook per l'autenticazione o il token di accesso dell'applicazione generato dal token di Facebook tramite una funzione "get_access_token" nell'API REST.
- Le app non browser hanno un po 'più difficile qui, perché OAuth richiede un browser Web per accedere. Per accedere da un'app per telefono o desktop è necessario avviare un browser per eseguire il reindirizzamento a Facebook e, peggio ancora, è necessario che il browser passi il token di accesso di Facebook all'applicazione tramite un meccanismo.
Spero che questo risponda alla maggior parte delle domande. Ovviamente puoi sostituire Facebook con Twitter, Google o qualsiasi altro servizio di autenticazione basato su OAuth.
Sarei interessato a sapere se qualcuno ha un modo più semplice per affrontarlo.
passport-facebook
. Dopo aver funzionato, il passaggio successivo è iniziare a capire come funziona Passport e come memorizza le credenziali. Collegarlo a Restify ( vedi qui per una versione aggiornata di quella che hai citato) sarebbe uno degli ultimi passaggi (o potresti implementare l'interfaccia REST in Express).