2016-10-28 184 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