passport-local với node-jwt-simple


87

Làm cách nào để kết hợp passport-local để trả lại mã thông báo JWT khi xác thực thành công?

Tôi muốn sử dụng node-jwt-simple và nhìn vào passport.js, tôi không biết phải làm thế nào.

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

Có thể trả lại mã thông báo khi gọi done () không? Một cái gì đó như thế này ... (chỉ là mã giả)

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

Nếu không, tôi có thể trả lại mã thông báo bằng cách nào?

Câu trả lời:


123

Tôi đã hiểu rồi!

Trước hết bạn cần thực hiện chiến lược chính xác. Trong trường hợp của tôi là LocalStrategy và bạn cần cung cấp logic xác thực của mình. Ví dụ vì lợi ích, hãy sử dụng một trong hộ chiếu-địa phương.

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

cuộc gọi lại xác minh mà bạn cung cấp function(username, password, done)sẽ thực hiện việc tìm kiếm người dùng của bạn và kiểm tra xem mật khẩu có khớp không (ngoài phạm vi câu hỏi và câu trả lời của tôi)

passport.js mong đợi một số phần để nó hoạt động, một là bạn trả lại người dùng trong chiến lược. Tôi đã cố gắng thay đổi phần đó của mã, và điều đó đã sai. Cuộc gọi lại dự kiến falsenếu xác thực không thành công và object(người dùng đã xác thực) nếu bạn thành công.

Bây giờ .... làm thế nào để tích hợp JWT?

Trong lộ trình đăng nhập, bạn sẽ phải xử lý xác thực thành công hoặc không thành công. Và chính ở đây bạn cần thêm phần tạo mã thông báo JWT. Như vậy:

(hãy nhớ vô hiệu hóa phiên, nếu không bạn sẽ phải triển khai các chức năng tuần tự hóa và giải mã hóa. Và bạn không cần các chức năng này nếu bạn không duy trì phiên, bạn không cần nếu bạn đang sử dụng xác thực dựa trên mã thông báo)

Từ ví dụ hộ chiếu-địa phương: (có thêm mã thông báo 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);
});

Và đó là nó! Bây giờ khi bạn gọi / đăng nhập và ĐĂNG tên người dùng và mật khẩu (phải luôn qua SSL) đoạn mã đầu tiên ở trên sẽ cố gắng tìm người dùng dựa trên tên người dùng bạn đã cung cấp và sau đó kiểm tra xem mật khẩu có khớp không (Tất nhiên bạn sẽ cần thay đổi cho phù hợp với nhu cầu của bạn).

Sau đó, tuyến đường đăng nhập của bạn sẽ được gọi và ở đó bạn có thể xử lý việc trả lại lỗi hoặc mã thông báo hợp lệ.

Hy vọng điều này sẽ giúp một ai đó. Và nếu tôi có bất kỳ sai lầm hoặc quên điều gì đó, hãy cho tôi biết.


3
Passport's BasicStrategy hoặc DigestStrategy là hai tùy chọn khác. Mặc dù vậy, dường như không có sự khác biệt lớn giữa chiến lược Cơ bản và Địa phương vì không cần phiên hoạt động - chỉ là Địa phương yêu cầu URL chuyển hướng (làm cho nó hơi kém thân thiện với API).
funseiki

1
Xin chào @cgiacomi, bạn có thể cho ví dụ về một tuyến đường kiểm tra mã thông báo không?
Matt Kim

3
Này @ matt-kim thực ra tôi không lưu mã thông báo, nó chỉ là tạm thời thôi. Tôi không biết liệu đó có phải là cách tốt nhất hay không nhưng đây là những gì tôi làm: Người dùng xác thực và tôi tạo mã thông báo và trả lại cho khách hàng. Mã thông báo được lưu trữ trong localStorage nếu khách hàng là một trang web hoặc bạn có thể lưu trữ nó trong ứng dụng iPhone / Android. Khi một khách hàng phải thực hiện một yêu cầu cho một tài nguyên, nó sẽ gửi mã thông báo đã lưu đến phần phụ trợ. Hộ chiếu sẽ xử lý mã thông báo. Đây là ý chính với chiến lược Bearer để xử lý mã thông báo gist.github.com/cgiacomi/cd1efa187b8cccbe2a61 Hy vọng điều này sẽ hữu ích! :)
cgiacomi

1
Này @cgiacomi! có thể đó là điều hiển nhiên, nhưng bạn có thể mô tả cách bạn vô hiệu hóa các phiên khi sử dụng lệnh gọi lại tùy chỉnh không?
MrMuh

2
@MrMuh kiểm tra các liên kết gist.github.com/cgiacomi/cd1efa187b8cccbe2a61 trong bình luận của tôi, tôi thấy làm thế nào để vô hiệu hóa phiên: passport.authenticate ( 'vô danh', {phiên: false})
cgiacomi

18

Đây là một giải pháp tuyệt vời, tôi chỉ muốn thêm điều này:

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

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

Tôi thích sử dụng "express-jwt" để xác thực mã thông báo.

btw: bài viết này rất tuyệt để tìm hiểu cách xử lý mã thông báo ở phía máy khách, sử dụng Angular, để gửi nó trở lại với mọi yêu cầu

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


2
Tôi chỉ sử dụng express-jwtđể xác thực, nhưng đọc qua tài liệu của các gói khác như passport-jwt, tôi nghĩ tôi sẽ tiếp tục express-jwt. Đơn giản hơn nhiều, nhiều hơn đẹp hơn IMO
bobbyz

Chỉ là một FYI express-jwt không cung cấp hỗ trợ làm mới mã thông báo.
user3344977

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.