2013-03-13 25 views
40

xin lỗi, tôi rất mới đối với node.js vì vậy tôi chưa thể kết thúc đầu của mình xung quanh vấn đề này. Tôi đang sử dụng Node.js làm máy chủ API phụ trợ cho máy khách iPhone. Tôi đang sử dụng Passport.js để xác thực bằng chiến lược Địa phương. Các mã có liên quan là dưới đây:Gửi lại phản hồi JSON khi không xác thực Passport.js

// This is in user.js, my user model 
UserSchema.static('authenticate', function(username, password, callback) { 
    this.findOne({ username: username }, function(err, user) { 
     if (err){ 
      console.log('findOne error occurred'); 
      return callback(err); 
     } 
     if (!user){ 
      return callback(null, false); 
     } 
     user.verifyPassword(password, function(err, passwordCorrect){ 
      if (err){ 
       console.log('verifyPassword error occurred'); 
       return callback(err); 
      } 
      if (!passwordCorrect){ 
       console.log('Wrong password'); 
       return callback(err, false); 
      } 
      console.log('User Found, returning user'); 
      return callback(null, user); 
     }); 
    }); 
}); 

// This is in app.js 
app.get('/loginfail', function(req, res){ 
    res.json(403, {message: 'Invalid username/password'}); 
}); 

app.post('/login', 
    passport.authenticate('local', { failureRedirect: '/loginfail', failureFlash: false }), 
    function(req, res) { 
     res.redirect('/'); 
}); 

Ngay bây giờ, tôi đã quản lý để chuyển hướng một tên đăng nhập thất bại trong việc/loginfail, nơi tôi gửi lại một số JSON cho khách hàng iPhone. Tuy nhiên, điều này không có đủ chi tiết. Tôi muốn có thể gửi lại các lỗi thích hợp cho ứng dụng khách iPhone, chẳng hạn như: "Không tìm thấy người dùng" hoặc "Mật khẩu sai". Với mã hiện tại của tôi, tôi không thấy làm thế nào điều này có thể được thực hiện.

Tôi đã cố gắng làm theo các ví dụ cho một cuộc gọi lại tùy chỉnh trên trang web passport.js, nhưng tôi không thể làm cho nó hoạt động do thiếu sự hiểu biết về nút. Làm cách nào tôi có thể sửa đổi mã của mình để tôi có thể gửi lại tệp res.json với mã/thông báo lỗi thích hợp?

EDIT: Tôi đang cố gắng một cái gì đó như thế này bây giờ:

// In app.js 
app.post('/login', function(req, res, next) { 
    passport.authenticate('local', function(err, user, info) { 
     if (err) { return next(err) } 
     if (!user) { 
      console.log(info); 
      // *** Display message without using flash option 
      // re-render the login form with a message 
      return res.redirect('/login'); 
     } 
     console.log('got user'); 
     return res.json(200, {user_id: user._id}); 
    })(req, res, next); 
}); 

// In user.js 
UserSchema.static('authenticate', function(username, password, callback) { 
    this.findOne({ username: username }, function(err, user) { 
     if (err){ 
      console.log('findOne error occurred'); 
      return callback(err); 
     } 
     if (!user){ 
      return callback(null, false); 
     } 
     user.verifyPassword(password, function(err, passwordCorrect){ 
      if (err){ 
       return callback(err); 
      } 
      if (!passwordCorrect){ 
       return callback(err, false, {message: 'bad password'}); 
      } 
      console.log('User Found, returning user'); 
      return callback(null, user); 
     }); 
    }); 
}); 

Nhưng trở lại khi tôi cố gắng console.log (thông tin), nó chỉ nói không xác định. Tôi không biết làm thế nào để có được gọi lại tùy chỉnh này làm việc ... Bất kỳ trợ giúp sẽ được đánh giá cao!

Trả lời

19

Tôi tin rằng chức năng gọi lại mà các cuộc gọi tĩnh 'xác thực' của bạn (được gọi là 'gọi lại' trong mã của bạn) chấp nhận thông số thứ 3 - "thông tin" - mà mã của bạn có thể cung cấp. Sau đó, thay vì truyền vào đối tượng {failureRedirect: ...}, hãy truyền vào một hàm lấy 3 đối số - err, user và info. "Thông tin" mà bạn cung cấp trong phương thức xác thực sẽ được chuyển tới cuộc gọi lại này.

Hộ chiếu gọi kịch bản này là "gọi lại tùy chỉnh". Xem tài liệu tại đây: http://passportjs.org/guide/authenticate/

+0

Cảm ơn bạn cho việc này. Tôi nhận thức được gọi lại tùy chỉnh, nhưng vấn đề của tôi là tôi chỉ không hiểu làm thế nào để thực hiện nó (xin lỗi rất mới đến nút và js). Tôi đã chỉnh sửa câu hỏi của mình với những nỗ lực mới nhất của tôi. Như bạn có thể thấy, tôi đang cố gắng sử dụng thông số "thông tin" này, nhưng tôi không biết cách sử dụng nó một cách chính xác - nó luôn luôn không được xác định khi tôi lấy lại từ xác thực. – kurisukun

+0

Xin lỗi, tôi đã chỉ ra rằng tôi cần phải thêm "thông tin" vào điều này: passport.use (new LocalStrategy (chức năng (tên người dùng, mật khẩu, đã hoàn tất) { User.authenticate (tên người dùng, mật khẩu, chức năng (err) , người dùng, thông tin) { trả lại xong (err, người dùng, thông tin); }); } )); – kurisukun

+0

Cuộc trò chuyện này đã giúp tôi đi đến cùng một kết luận với một chút chất hơn. https://github.com/jaredhanson/passport/issues/255 – jpierson

42

Tôi gặp sự cố tương tự với Hộ chiếu và phản hồi đăng nhập không thành công. Tôi đã xây dựng một API và muốn tất cả các phản hồi được trả về dưới dạng JSON. Hộ chiếu trả lời mật khẩu không hợp lệ với trạng thái: 401 và nội dung: "Không được ủy quyền". Đó chỉ là một chuỗi văn bản trong cơ thể, chứ không phải JSON, vì vậy nó đã phá vỡ khách hàng của tôi mà dự kiến ​​tất cả JSON.

Khi nó quay ra, có một cách để làm cho hộ chiếu chỉ trả lại lỗi cho khuôn khổ thay vì cố gắng để gửi một phản ứng chính nó.

Câu trả lời là để thiết lập failWithError trong các tùy chọn thông qua để xác thực: https://github.com/jaredhanson/passport/issues/126#issuecomment-32333163

Từ bình luận jaredhanson trong vấn đề này:

app.post('/login', 
    passport.authenticate('local', { failWithError: true }), 
    function(req, res, next) { 
    // handle success 
    if (req.xhr) { return res.json({ id: req.user.id }); } 
    return res.redirect('/'); 
    }, 
    function(err, req, res, next) { 
    // handle error 
    if (req.xhr) { return res.json(err); } 
    return res.redirect('/login'); 
    } 
); 

này sẽ gọi xử lý lỗi sau Passport gọi next(err). Đối với ứng dụng của tôi, tôi đã viết một handler lỗi generic cụ thể cho trường hợp sử dụng của tôi chỉ cung cấp một lỗi JSON:

// Middleware error handler for json response 
function handleError(err,req,res,next){ 
    var output = { 
     error: { 
      name: err.name, 
      message: err.message, 
      text: err.toString() 
     } 
    }; 
    var statusCode = err.status || 500; 
    res.status(statusCode).json(output); 
} 

Sau đó, tôi sử dụng nó cho tất cả các tuyến api:

var api = express.Router(); 
... 
//set up some routes here, attached to api 
... 
// error handling middleware last 
api.use([ 
     handleError 
     ]); 

tôi không tìm thấy tùy chọn failWithError trong tài liệu. Tôi stumbled khi nó trong khi truy tìm thông qua các mã trong trình gỡ lỗi.

Ngoài ra, trước khi tôi tìm ra điều này, tôi đã thử "gọi lại tùy chỉnh" được đề cập trong câu trả lời @Kevin_Dente, nhưng nó không hoạt động đối với tôi. Tôi không chắc đó có phải là phiên bản cũ của Hộ chiếu hay không, nếu tôi làm sai.

+4

điều này vẫn hoạt động trong năm 2016. cảm ơn! – iPhoney

+2

vẫn còn hiệu lực vào năm 2017 LOL –

+1

vẫn hợp lệ. : P –

1

Có một tài liệu chính thức cho Tuỳ chỉnh Callback:

app.get('/login', function(req, res, next) { 
    passport.authenticate('local', function(err, user, info) { 
    if (err) { return next(err); } 
    if (!user) { return res.redirect('/login'); } 
    req.logIn(user, function(err) { 
     if (err) { return next(err); } 
     return res.redirect('/users/' + user.username); 
    }); 
    })(req, res, next); 
}); 

https://github.com/passport/www.passportjs.org/blob/master/views/docs/authenticate.md

1

Bạn có thể làm điều đó mà không cần callbacks tùy chỉnh sử dụng tài sản "passReqToCallback" trong định nghĩa chiến lược của bạn:

passport.use(new LocalStrategy({passReqToCallback: true}, validateUserPassword)); 

Sau đó, bạn có thể thêm mã lỗi xác thực tùy chỉnh vào yêu cầu trong hợp tác chiến lược của mình de:

var validateUserPassword = function (req, username, password, done) { 
    userService.findUser(username) 
     .then(user => { 
      if (!user) { 
       req.authError = "UserNotFound"; 
       return done(null, false); 
      } 

Và cuối cùng bạn có thể xử lý các lỗi này tùy chỉnh trong lộ trình của bạn:

app.post('/login', passport.authenticate('local', { failWithError: true })  
    function (req, res) { 
     .... 
    }, function(err, req, res, next) { 
     if(req.autherror) { 
      res.status(401).send(req.autherror) 
     } else { 
      .... 
     } 
    } 
); 
Các vấn đề liên quan