2013-10-24 13 views
6

Od kilku dni rozwijam swój pierwszy system uwierzytelniania użytkownika za pomocą Passport.js. Niezręcznie, skończyłem to i działa zgodnie z przeznaczeniem. Problem polega na tym, że mimo że przeczytałem wiele artykułów i sprawdziłem dziesiątki przykładów w Internecie, wydaje mi się, że nie rozumiem całego kodu jako takiego. Nie mam problemów ze zrozumieniem procesu, który za tym stoi i dlaczego tak się dzieje. Byłbym bardzo wdzięczny, gdybyś mógł mi wyjaśnić niektóre części kodu. Jest to kod roboczy, przechowywany w moim app.js pliku:Logowanie użytkownika i uwierzytelnianie Passport.js

// Passport session setup 
passport.serializeUser(function (user, done) { 
    done(null, user._id); 
}); 

passport.deserializeUser(function (id, done) { 
    User.findById(id, function(err, user) { 
     done(err, user); 
    }); 
}); 

// Use the Local Strategy within passport 
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: 'Unknown user: ' + username}); 
     } 

     user.comparePassword(password, function(err, isMatch) { 
      if (err) { 
       return done(err); 
      } 

      if (isMatch) { 
       return done(null, user); 
      } else { 
       return done(null, false, { message: 'Invalid Password' }); 
      } 
     }); 
    }); 
})); 

var app = module.exports = express(); 

app.configure(function() { 
    app.set('views', path.join(__dirname + '/views')); 
    app.set('view engine', 'html'); 
    app.engine('html', hbs.__express); 
    app.use(express.logger()); 
    app.use(express.cookieParser()); 
    app.use(express.bodyParser()); 
    app.use(express.methodOverride()); 
    app.use(express.session({ secret: 'xxx' }));  
    app.use(passport.initialize()); 
    app.use(passport.session()); 
    app.use(app.router); 
    app.use(express.static(path.join(__dirname + '/public'))); 

}); 

Używam MongoDB (User - model mangusta). Ponadto do przechowywania haseł w bazie danych używam obecnie bcrypt.

Myślę, że najbardziej krytyczną częścią, której tutaj nie rozumiem, jest funkcja oddzwaniania done. Rozumiem, że po prostu przekazuje pewne wartości, a ja wiem tyle, aby zdać sobie sprawę, że pierwszym parametrem jest błąd, a drugi dane. Nadal nie w pełni to rozumiem, ponieważ nie podałem konkretnie jednego jako parametru. Na przykład, jeśli będę mieć funkcję tak:

// Random Function 
var randomFunction = function (a, b, done) { 
    done(a, b); 
}; 

// Then I would call the randomFunction providing my own **done** 
randomFunction('Random', 'Words', function(a, b) { return a + b; }); 

Mimo to, w moim przykładzie, że nie jestem jednym z określeniem zrobić zwrotnego. Jest to po prostu wymagany parametr funkcja zwrotna czy jest taka sama jak następnej funkcji w normalnym middleware, takie jak:

function middleware (req, res, next) { 
    next(req.user); // pass the req.user to next middleware 
} 

Ponadto, skąd Passport.js wiążą użytkownika, że ​​to obsługuje? Czy wiąże go do req.user? Jak mogę przekazać to do niektórych widoków w celu na przykład wyświetlenia nazwy użytkownika?

Z niecierpliwością czekam na Wasze opinie!

Dziękujemy!

Odpowiedz

3

Gotowe zwrotna

Spójrz na kodzie Local Strategy:

function Strategy(options, verify) { 
    ... 
    this._verify = verify; 
    ... 
} 

verify jest funkcją, która będzie używana przez strategię w celu weryfikacji użytkownika i masz określone tutaj:

passport.use(new LocalStrategy(function (username, password, done) { 
    // your verification code here 
})); 

Później w strategii można znaleźć metodę authenticate, która wywołuje funkcję weryfikacji z etapu powyżej:

this._verify(username, password, verified); 

Więc teraz zobaczyć gdzie username, password i done==verified pochodzą. Później w twoim kodzie wywołasz wywołanie zwrotne done z argumentami (err, user, info). W kilku słowach potrzebna jest done do zakończenia asynchronicznej procedury weryfikacji użytkownika.

req.user i widoki

Tak, masz rację o req.user.Więc można przekazać je do swoich poglądów na dwa sposoby:

  1. jako argument res.render funkcji. See docs

    res.render('some-template', { name: req.user }); 
    
  2. Zastosowanie res.locals jako pewnego rodzaju dostawcy kontekstowego (obecnie obiekt użytkownika będzie dostępny we wszystkich widokach, które są zdefiniowane w app.router). See docs

    // before app.use(app.router); 
    app.use(function(req, res, next) { 
        res.locals.user = req.user; 
        next(); 
    }); 
    
+0

Dziękuję bardzo za odpowiedź! Jak rozumiem, gotowe jest funkcja wywołania zwrotnego, która służy do zwracania informacji z oprogramowania pośredniego. Przez informację mam na myśli 3 parametry (err, user, info). Zasadniczo, czy mogę uznać, że wykonane wywołanie zwrotne jest (na wysokim poziomie) powrotem tego konkretnego oprogramowania pośredniego? –

+1

Jeśli dobrze zrozumiałem twoje pytanie, nie. 'done' służy tylko do przekazania niektórych danych do następnego poziomu. Twój kod weryfikacyjny zostanie wykonany w normalny sposób po wywołaniu 'done()', dlatego powinieneś użyć 'return done (err);' aby przerwać wykonywanie kodu weryfikacyjnego. Jest to typowy przypadek asynchronizacji. –

+0

To właśnie miałem na myśli ^^ Myślę, że w mojej odpowiedzi byłam nieco niejednoznaczna :) Dziękuję bardzo za twoją opinię, naprawdę to doceniam! –

Powiązane problemy