passportjs是一个提供authentication服务的node中间件。通常用于expressjs web application的验证。passportjs提供了很多的strategies,每一个strategy是对一种验证方式的封装。比如passport-local,常规的使用本地验证,一般用户信息存在数据库中。
在我的学习过程中,使用了passport-local作为验证的strategy。
在基于expressjs的web applicationg中使用passportjs通常需要处理如下几部分代码:
- 初始化passportjs
- 设置strategy
- 写/login的get,post方法
- 序列化
- 对需要验证后登陆的页面保护
初始化passportjs
app.use(session({ secret: 'keyboard cat' , resave: false, saveUninitialized: false}));
app.use(passport.initialize());
app.use(passport.session());
如果不使用session的话,可以去除session的部分。
设置strategy
在login.js中设置strategy.
当发生用户或密码错误时,callback使用done(null,false)。因为用户名或密码错误不代表是程序的错误,所以不抛出错误。
findByUsername为寻找username object的function。里面可以封装在数据库中查找的方法。
var passport = require('passport')
, LocalStrategy = require('passport-local').Strategy;
passport.use(new LocalStrategy(
function(username, password, done) {
findByUsername(username, function(err, user) {
if (err) { return done(err); }
if (!user) { return done(null, false); }
if (user.password != password) { return done(null, false); }
return done(null, user);
});
}
));
写/login的get,post方法
此段代码在login.js中。在app.js中已经设置app.use('/login', logins);
所以这里的路径都是用/
。在收到post方法的请求时,调用callback passport.authenticate('local')
,即调用了passport的local strategy进行验证。如果通过验证,passport会设置req.user对象。并且req.isAuthenticated()
将返回true
。
router.get('/', function(req, res, next) {
res.render('login', { title: 'Login' });
});
router.post('/', passport.authenticate('local', { successRedirect: 'http://localhost:3000', failureRedirect: '/login' }));
序列化
在passportjs的文档中,并没有出现序列化相关的内容。但是在没有使用序列化的方法处理对象前访问页面会报序列化的错误。所以这里要自定义passport的序列化方法。
在serializeUser方法中,尽量使用少的属性定义一个唯一的实体。这里使用user.username进行serialize。在deserializeUser方法中,使用唯一属性获得完整对象。一般可以访问数据库获得需要的属性。这里简化为{username:username}
。
passport.serializeUser(function(user,done){
done(null,user.username);
});
passport.deserializeUser(function(username,done){
done(null,{username:username});
});
对需要验证后登陆的页面保护
如果某个页面需要登录后访问,可以在相关的handler中判断req.isAuthenticated()
的返回值。
router.get('/', function(req, res, next) {
if(req.isAuthenticated()){
console.log(req.isAuthenticated());
res.render('index', { title: 'Express' });
}
else{
res.redirect('/login');
}
});
如果有很多页面需要保护,可以抽象出此部分逻辑放到一个function中。然后把这个function放到router.get的callback chain里即可。
var isAuthenticated = function (req,res,next) {
if (req.isAuthenticated()) return next();
res.redirect('/login');
}
router.get('/', isAuthenticated ,function(req, res, next)...