2016-10-28 323 views
1

我在使用護照本地策略執行我的restful api身份驗證時遇到了混淆問題。身份驗證問題

說明: 當我在index.js中完成所有操作時,我的認證工作成功。但我想在類中使用更好的代碼分離。

我有一個passport.js模塊

// config/passport.js 

// load all the things we need 
var LocalStrategy = require('passport-local').Strategy; 
// load up the user model 
var mysql = require('mysql'); 
var dbconfig = require('./database'); 
var connection = mysql.createConnection(dbconfig.connection); 

module.exports = function(passport) { 

// passport needs ability to serialize and unserialize users out of session 
    passport.serializeUser(function (user, done) { 
     //console.log("SER"); 
     console.log(user), 
     done(null, user); 
    }); 
    passport.deserializeUser(function (user, done) { 
     console.log("XXXX"); 
     console.log(user); 
     connection.query("SELECT * FROM users WHERE name = ? ",user.name, function(err, rows){ 
      console.log("DER"); 
      console.log(rows); 
      done(err, rows[0]); 
     }); 
    }); 

// passport local strategy for local-login, local refers to this app 
    passport.use('local-login', new LocalStrategy(
     function (username, password, done) { 
      console.log("hhh"); 
      console.log(username); 
      connection.query("SELECT * FROM users WHERE name = ? ",username, function(err, rows){ 
       console.log(rows); 
       return done(err, rows[0]); 
      }); 
     }) 
    ); 

    // route middleware to ensure user is logged in 
    function isLoggedIn(req, res, next) { 
     if (req.isAuthenticated()) 
      return next(); 

     res.sendStatus(401); 
    } 
}; 

這是我的控制器類:

class AuthenticateController { 
    constructor(router, passport) { 
     this.router = router; 
     this.registerRoutes(); 
     this.passport = passport; 
    } 

    registerRoutes() { 
     this.router.post('/login/:username/:password', this.login.bind(this)); 
     //this.router.get('/logout', this.logout.bind(this)); 
     this.router.get('/content', this.content.bind(this)); 
    } 

    login(req, res) { 
     this.passport.authenticate("local-login", { failureRedirect: "/login"}), 
      res.redirect("/content"); 
    } 

    content(req, res) { 
     console.log(req.user); 
     if (req.isAuthenticated()) { 
      res.send("Congratulations! you've successfully logged in.") 
     } else { 
      res.sendStatus(401); 
     } 
    } 
    isLoggedIn(req, res, next) { 
    console.log(req.user); 
    if (req.isAuthenticated()) 
     return next(); 

    res.sendStatus(401); 
} 
} 

module.exports = AuthenticateController; 

控制器獲取路由器和護照完全配置爲從我index.js參數。

//index.js

var express = require('express') 
    , cors = require('cors') 
    , app = express() 
    , passport = require('passport') 
    , morgan = require('morgan'); 

require('./config/passport')(passport); // pass passport for configuration 

var bodyParser = require('body-parser'); 
app.use(bodyParser.json()); 
app.use(require('express-session')({secret: 'vidyapathaisalwaysrunning', 
    resave: true, 
    saveUninitialized: true })); 

app.use(passport.initialize()); 
app.use(passport.session()); 
app.use(cors()); 

var apiRouter = express.Router(); 
app.use('/api', apiRouter); 
// 
var apiV1 = express.Router(); 
apiRouter.use('/v1', apiV1); 

var authenticateApiV1 = express.Router(); 
apiV1.use('/auth', authenticateApiV1); 

var AuthenticateController = require('./controllers/authenticate'); 
var ac = new AuthenticateController(authenticateApiV1, passport); //pass in our fully configured passport 

//If I call this /login instead of the /auth/login/ in the Controller Class it works! 
//app.post("/login", 
// passport.authenticate("local-login", { failureRedirect: "/login"}), 
// function (req, res) { 
//  res.redirect("/content"); 
// }); 

什麼是工作,什麼是不工作

的認證以一般工作。在我發佈的index.js中,你會看到app.post("/login", ...。如果我呼叫此身份驗證成功,並且如果我嘗試訪問受限內容 in/auth/content/req.user有一個值(用戶對象),並且我可以成功呼叫req.isAuthenticated()

但是,如果我使用/auth/login/username/password的驗證,req.user未定義當試圖達到受限制的內容。 我得到沒有錯誤和/auth/login/username/password/ HTTP代碼301 - '重定向到/內容的迴應。

我目前不知道什麼I'm做錯了,並I'm相當新的節點/快遞/護照的話題..

希望有人有一個想法。如果您需要別的幫助我,請在評論中提及它,我會盡我所能爲您提供您所需的一切。

感謝

編輯:

我最近嘗試在登錄功能來讀取req.user,甚至還有它是不確定的

login(req, res) { 
     this.passport.authenticate("local-login", { failureRedirect: "/login"}), 
      console.log(req.user) //undefined 
      res.redirect("/content"); 
    } 

我想這可能是一些異步的問題,我應該使用一些回調函數,但我不知道如何將其應用於我的login()

編輯2:

我正面臨的另一個問題是isLoggedIn()請求的集成。

如果我這樣做:

registerRoutes() { 
       this.router.get('/', this.isLoggedIn, this.getUsers.bind(this)); 
       this.router.get('/:id', this.getSingleUser.bind(this)); 
      } 

它導致401 - Unauthorized

一個console.log(req.user);isLoggedIn()結果不確定。

但是,如果我呼叫第一條路線而不呼叫isLoggedIn()並且執行console.log(req.user);用戶對象存在。

回答

1

正確使用回撥與Passport身份驗證本地策略可以如下:

function(req, res, next){ passport.authenticate('local-login', function(err, user, info){ if(err) return logger.log('error', err); if(user) req.login(user, function(err){ if(err) return next(err); return res.json({'success': true}); }); if(!user) return res.json({'error':true, 'message': info.message, 'type': info.type}); })(req, res, next);
}

請注意使用req.login的()明確設置用戶以s分裂國家。

+0

感謝您的回答。您的解決方案是唯一的解決方案,我沒有遇到超時,它似乎工作!謝謝 –

+0

很高興我能幫到你。 – divsingh

1

我唯一覺得奇怪的是你的路由聲明是不同的。

AuthenticateController路線被聲明爲:

this.router.post('/login/:username/:password', ... 

雖然index.js,路由就只作爲

app.post("/login", ... 

如何在您的客戶端提交的登錄憑證到服務器申報?如果是the tutorial等形式,是否可以將:username:password聲明爲路由參數,但是是否通過護照形式發送?

嘗試註冊的路線完全一樣index.js

this.router.post('/login', ... 

編輯: 我發現了另一個dicrepancy。 AuthenticateControllerres.redirect("/content");不包含在回調中。所以它在Authenticate完成運行之前正在執行。

index.js例如,護照被用作路由中間件:

app.post("/login", 
    passport.authenticate("local-login", { failureRedirect: "/login"}), 
    function (req, res) { 
     res.redirect("/content"); 
    }); 

雖然在passport.js它是回調內部。考慮在航線它聲明:

registerRoutes() { 
    this.router.post('/login', this.passport.authenticate("local-login", { failureRedirect: "/login"}), this.login.bind(this)); 
    (...) 
} 

login(req, res) { 
    res.redirect("/content"); 
} 

O,更好的是,爲什麼不使用passport's option to declare both success and failure redirects,因爲這似乎是所有你正在做的:

login(req, res) { 
    this.passport.authenticate("local-login", { successRedirect: "/content", failureRedirect: "/login" }); 
} 
+0

找到,但它沒有幫助。我正在使用Chrome插件ARC發送請求。任何其他想法? –

+0

@elsololobo看看我的編輯。我提出了其他一些可以幫助您的更改 – fmello

1

你傳入this.login.bind(this)作爲中間件this.router.post('/login/:username/:password', this.login.bind(this));login(req, res)只響應該請求與res.redirect("/content");即重定向到/內容

所以就像你說的,你需要提供一個回調,做一些與用戶即從護照中間件返回的驗證回調。

app.post("/login", 
    passport.authenticate("local-login", { failureRedirect: "/login"}), 
    function (req, res) { 
    console.log(req.user); // log user in console 
    res.json({user: req.user}); // send user as json response 
}); 

通過@divsingh提到的定製回調是,如果你想明確地具有設置會話,錯誤消息和重定向請求的控制。任何其他信息可以在http://passportjs.org/docs