passport-local con node-jwt-simple


87

Come posso combinare passport-local per restituire un token JWT in caso di autenticazione riuscita?

Voglio usare node-jwt-simple e guardando passport.js non sono sicuro di come procedere.

var passport = require('passport')
  , LocalStrategy = require('passport-local').Strategy;

passport.use(new LocalStrategy(
  function(username, password, done) {
    User.findOne({ username: username }, function(err, user) {
      if (err) { return done(err); }
      if (!user) {
        return done(null, false, { message: 'Incorrect username.' });
      }
      if (!user.validPassword(password)) {
        return done(null, false, { message: 'Incorrect password.' });
      }
      return done(null, user);
    });
  }
));

È possibile restituire il token quando si chiama done ()? Qualcosa di simile ... (solo pseudo codice)

if(User.validCredentials(username, password)) {
  var token = jwt.encode({username: username}, tokenSecret);
  done(null, {token : token}); //is this possible?
}

In caso contrario, come posso restituire il token?

Risposte:


123

L'avevo capito!

Prima di tutto devi implementare la strategia corretta. Nel mio caso LocalStrategy e devi fornire la tua logica di convalida. Ad esempio, usiamo quello in passport-local.

var passport = require('passport')
  , LocalStrategy = require('passport-local').Strategy;

passport.use(new LocalStrategy(
  function(username, password, done) {
    User.findOne({ username: username }, function(err, user) {
      if (err) { return done(err); }
      if (!user) {
        return done(null, false, { message: 'Incorrect username.' });
      }
      if (!user.validPassword(password)) {
        return done(null, false, { message: 'Incorrect password.' });
      }
      return done(null, user);
    });
  }
));

la richiamata di verifica che fornisci function(username, password, done)si occuperà di trovare il tuo utente e controllare se la password corrisponde (oltre lo scopo della domanda e della mia risposta)

passport.js si aspetta che funzioni diverse, una è che tu restituisca l'utente nella strategia. Stavo cercando di cambiare quella parte del codice, ma era sbagliato. Il callback si aspetta falsese la convalida fallisce e un object(l'utente convalidato) se hai successo.

Ora .... come integrare JWT?

Nella tua rotta di accesso dovrai gestire un'autenticazione riuscita o una non riuscita. Ed è qui che devi aggiungere la creazione del token JWT. Così:

(ricorda di disabilitare la sessione, altrimenti dovrai implementare le funzioni di serializzazione e deserializzazione. E non ti servono se non stai persistendo la sessione, cosa che non sei se stai usando un'autenticazione basata su token)

Da esempi passport-local: (con il token JWT aggiunto)

// POST /login
//   This is an alternative implementation that uses a custom callback to
//   achieve the same functionality.
app.post('/login', function(req, res, next) {
  passport.authenticate('local', function(err, user, info) {
    if (err) { return next(err) }
    if (!user) {
      return res.json(401, { error: 'message' });
    }

    //user has authenticated correctly thus we create a JWT token 
    var token = jwt.encode({ username: 'somedata'}, tokenSecret);
    res.json({ token : token });

  })(req, res, next);
});

E questo è tutto! Ora quando chiami / accedi e POST nome utente e password (che dovrebbe essere sempre su SSL) il primo frammento di codice sopra proverà a trovare un utente in base al nome utente fornito e quindi controllerà che la password corrisponda (ovviamente dovrai cambiarlo in base alle proprie esigenze).

Dopodiché verrà chiamata la tua rotta di accesso e lì potrai occuparti di restituire un errore o un token valido.

Spero che questo possa aiutare qualcuno. E se ho fatto degli errori o ho dimenticato qualcosa fammelo sapere.


3
Del Passaporto BasicStrategy o DigestStrategy sono altre due opzioni. Non sembra esserci un'enorme differenza tra le strategie di base e locali, tuttavia, poiché nessuna delle due ha bisogno di sessioni per funzionare, solo che Local richiede URL di reindirizzamento (rendendola leggermente meno API friendly).
funseiki

1
Ehi @cgiacomi potresti fare un esempio di percorso che controlla il token?
Matt Kim

3
Ehi @ matt-kim in realtà non salvo il token, è transitorio. Non so se sia il modo migliore o meno, ma questo è quello che faccio: l'utente si autentica, io genero il token e lo restituisco al client. Il token viene archiviato in localStorage se il client è un sito Web oppure è possibile archiviarlo in un'app per iPhone / Android. Quando un client deve effettuare una richiesta per una risorsa, invia il token salvato al backend. Passport gestirà il token. Ecco una sintesi con la strategia Bearer per gestire il token gist.github.com/cgiacomi/cd1efa187b8cccbe2a61 Spero che questo aiuti! :)
cgiacomi

1
Hey @cgiacomi! forse è ovvio, ma potresti descrivere come disabiliti le sessioni quando usi la richiamata personalizzata?
MrMuh

2
@MrMuh controlla il link gist.github.com/cgiacomi/cd1efa187b8cccbe2a61 nel mio commento mostro come disabilitare le sessioni: passport.authenticate ('bearer', {session: false})
cgiacomi

18

Questa è un'ottima soluzione, voglio solo aggiungere questo:

var expressJwt = require('express-jwt');

app.use('/api', expressJwt({secret: secret}));

Mi piace usare "express-jwt" per convalidare il token.

btw: questo articolo è ottimo per imparare a gestire il token lato client, utilizzando Angular, in modo da rispedirlo ad ogni richiesta

https://auth0.com/blog/2014/01/07/angularjs-authentication-with-cookies-vs-token/


2
Ho usato solo express-jwtper eseguire l'autenticazione, ma leggendo la documentazione di altri pacchetti come passport-jwt, penso che mi atterrò a express-jwt. Molto più semplice, molto più
carino

Solo un express-jwt FYI non fornisce supporto per i token di aggiornamento.
user3344977

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.