2013-03-13 138 views
40

對不起,我對node.js非常陌生,所以我還沒有能夠繞過這個包裹。我使用Node.js作爲iPhone客戶端的後端API服務器。我使用Passport.js進行本地策略認證。相關代碼如下:發送失敗時發送JSON響應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('/'); 
}); 

現在,我已成功地重定向失敗的登錄/ loginfail,在那裏我一些JSON發送回iPhone客戶端。但是,這沒有足夠的粒度。我希望能夠將適當的錯誤發送回iPhone客戶端,例如:「找不到用戶」或「密碼錯誤」。用我現有的代碼,我不明白這是如何實現的。

我試圖按照passport.js站點上的自定義回調的示例,但由於缺乏節點理解,我無法使其工作。我怎樣才能修改我的代碼,以便能夠發送res.json和適當的錯誤代碼/消息?

編輯:我現在想是這樣的:

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

但回來時,我嘗試CONSOLE.LOG(信息),它只是說不確定。我不知道如何得到這個自定義回調工作...任何幫助將不勝感激!

回答

19

我相信你的'認證'靜態調用(在你的代碼中稱爲「回調」)的回調函數接受第三個參數 - 「信息」 - 你的代碼可以提供。然後,不要傳入{failureRedirect:...}對象,而是傳入一個需要3個參數的函數 - err,user和info。您在驗證方法中提供的「信息」將傳遞給此回調。

護照將此場景稱爲「自定義回調」。看到文檔在這裏: http://passportjs.org/guide/authenticate/

+0

感謝你爲這個。我知道自定義回調,但我的問題是我不明白如何實現它(對於節點和js非常抱歉)。我用我的最新努力編輯了我的問題。正如你所看到的,我試圖使用這個「info」參數,但我不知道如何正確使用它 - 當我從身份驗證返回時它總是未定義的。 – kurisukun 2013-03-14 02:53:18

+0

對不起,我剛纔發現我還需要添加「info」以及: passport.use(新的LocalStrategy(函數(用戶名,密碼,完成)){User.authenticate(username,password,function(err ,user,info){ return done(err,user,info); }); } )); – kurisukun 2013-03-14 02:55:20

+0

這次對話使我得出了一個更具實質性的結論。 https://github.com/jaredhanson/passport/issues/255 – jpierson 2016-01-11 20:43:52

42

我有一個類似的問題,Passport和失敗的登錄響應。我正在構建一個API,並希望所有響應都以JSON的形式返回。 Passport響應一個無效的密碼,狀態爲:401,body:「未經授權」。這只是一個正文中的文本字符串,而不是JSON,所以它打破了我的客戶端,期望所有的JSON。

事實證明,有一種方法可以讓Passport將錯誤返回給框架,而不是嘗試發送響應本身。

答案是設置failWithError在通過驗證的選項: https://github.com/jaredhanson/passport/issues/126#issuecomment-32333163

從問題jaredhanson的評論:

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

這將調用錯誤處理程序調用護照後next(err)。對於我的應用程序,我寫了具體的一般錯誤處理程序的只是提供了一個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); 
} 

然後我用了所有的API路線:

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

我沒找到文檔中的failWithError選項。我在調試器中追蹤代碼時偶然發現了它。

另外,在我想出來之前,我嘗試了@Kevin_Dente答案中提到的「自定義回調」,但它對我無效。我不確定這是否適用於較早版本的護照,或者我只是做錯了。

+4

這仍然適用於2016年。謝謝! – iPhoney 2016-04-30 14:01:54

+2

2017年仍有效LOL – 2017-04-18 00:21:26

+1

仍有效。 :P – 2017-07-19 07:44:54

1

沒有爲自定義回調的官方文檔:

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

你可以做,沒有在你的策略定義使用屬性 「passReqToCallback」 定製回調:

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

然後,您可以將您的自定義身份驗證錯誤代碼添加到策略公司的請求中德:

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

最後,你可以處理你的路線這些自定義錯誤:

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