passport-local z node-jwt-simple

87

Jak mogę połączyć dane lokalne z paszportu, aby zwrócić token JWT po pomyślnym uwierzytelnieniu?

Chcę używać node-jwt-simple i patrząc na passport.js , nie wiem, jak się do tego zabrać.

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);
    });
  }
));

Czy można zwrócić token podczas wywoływania funkcji done ()? Coś takiego ... (tylko pseudo kod)

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

Jeśli nie, jak mogę zwrócić token?

cgiacomi
źródło

Odpowiedzi:

123

Rozgryzłem to!

Przede wszystkim musisz wdrożyć odpowiednią strategię. W moim przypadku LocalStrategy i musisz podać swoją logikę walidacji. Na przykład sake użyjmy tego w paszporcie lokalnym.

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);
    });
  }
));

oddzwonienie weryfikacyjne, które podasz function(username, password, done), zajmie się odnalezieniem Twojego użytkownika i sprawdzeniem zgodności hasła (poza zakresem pytania i mojej odpowiedzi)

passport.js oczekuje, że zadziała kilka elementów, jednym z nich jest zwrócenie użytkownika w strategii. Próbowałem zmienić tę część kodu i to było złe. Wywołanie zwrotne oczekuje, falsejeśli walidacja się nie powiedzie, i object(zweryfikowanego użytkownika), jeśli zakończy się pomyślnie.

Teraz… jak zintegrować JWT?

Na swojej trasie logowania będziesz musiał obsłużyć udaną lub nieudaną autoryzację. I to tutaj musisz dodać tworzenie tokena JWT. Tak jak to:

(pamiętaj, aby wyłączyć sesję, w przeciwnym razie będziesz musiał zaimplementować funkcje serializacji i deserializacji. I nie potrzebujesz ich, jeśli nie utrzymujesz sesji, czego nie jesteś, jeśli używasz uwierzytelniania opartego na tokenach)

Z lokalnych przykładów paszportowych: (z dodanym tokenem JWT)

// 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);
});

I to jest to! Teraz, gdy dzwonisz / logujesz się i POST nazwa użytkownika i hasło (które zawsze powinny być przez SSL), pierwszy fragment kodu powyżej spróbuje znaleźć użytkownika na podstawie podanej nazwy użytkownika, a następnie sprawdź, czy hasło jest zgodne (oczywiście będziesz musiał zmień to do swoich potrzeb).

Następnie zostanie wywołana Twoja trasa logowania i tam możesz zająć się zwróceniem błędu lub ważnego tokena.

Mam nadzieję, że to komuś pomoże. A jeśli popełniłem jakieś błędy lub zapomniałem o czymś, daj mi znać.

cgiacomi
źródło
3
Passport's BasicStrategy lub DigestStrategy to dwie inne opcje. Wydaje się jednak, że nie ma dużej różnicy między strategiami podstawowymi i lokalnymi, ponieważ żadna z nich nie potrzebuje sesji - po prostu lokalna prosi o przekierowanie adresów URL (co czyni ją nieco mniej przyjazną dla API).
funseiki
1
Hej @cgiacomi, czy możesz podać przykład trasy, która sprawdza token?
Matt Kim
3
Hej @ matt-kim właściwie nie zapisuję tokena, to jest przejściowe. Nie wiem, czy to najlepszy sposób, czy nie, ale oto co robię: użytkownik uwierzytelnia się, a ja generuję token i zwracam go klientowi. Token jest przechowywany w localStorage, jeśli klient jest witryną internetową lub możesz go przechowywać w aplikacji na iPhone'a / Androida. Gdy klient musi zażądać zasobu, wysyła zapisany token do zaplecza. Paszport obsłuży token. Oto sedno strategii Bearer do obsługi tokena gist.github.com/cgiacomi/cd1efa187b8cccbe2a61 Mam nadzieję, że to pomoże! :)
cgiacomi
1
Hej @cgiacomi! może to oczywiste, ale czy mógłbyś opisać, jak wyłączyć sesje podczas korzystania z niestandardowego wywołania zwrotnego?
MrMuh,
2
@MrMuh sprawdź link gist.github.com/cgiacomi/cd1efa187b8cccbe2a61 w moim komentarzu pokazuję, jak wyłączyć sesje: passport.authenticate ('bearer', {session: false})
cgiacomi
18

To świetne rozwiązanie, chcę tylko dodać to:

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

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

Lubię używać "express-jwt" do walidacji tokena.

btw: ten artykuł jest świetny, aby dowiedzieć się, jak obsługiwać token po stronie klienta za pomocą Angular, aby odsyłać go z każdym żądaniem

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

ZeroCR
źródło
2
Kiedyś tylko express-jwtdokonywałem uwierzytelniania, ale czytałem dokumentację innych pakietów, takich jak passport-jwt, myślę, że będę się trzymać express-jwt. O wiele prostsze, dużo ładniejsze IMO
bobbyz
Tylko FYI express-jwt nie zapewnia obsługi tokenów odświeżania.
user3344977