使用Passport实现认证需要配置三方面:
Passport uses what are termed strategies to authenticate requests. 策略的范围包括username和password,授权认证使用 OAuth,开放认证使用OpenID.
使用Passport之前, strategy (or strategies) 必须配置好。
Strategies可以通过 use()
函数来实现。 如下使用LocalStrategy
实现 username/password 认证
var passport = require('passport')
, LocalStrategy = require('passport-local').Strategy;
passport.use(new LocalStrategy(
function(username, password, done) {
User.findOne({ username: username }, function (err, user) {
if (err) { return done(err); }
if (!user) {
return done(null, false, { message: 'Incorrect username.' });
}
if (!user.validPassword(password)) {
return done(null, false, { message: 'Incorrect password.' });
}
return done(null, user);
});
}
));
上述事例介绍了一个很重要的概念,. Strategies 需要一个 verify callback,目的是找到拥有凭证的user。
当Passport认证一个请求时,他解析请求包含的凭证,然后他调用回调函数使用这些凭证作为参数,当前为 username
and password
. ,如果有效,执行 done
返回给Passport经过认证的用户。
return done(null, user);
如果凭证无效,(例如,密码是错的)。 done
应当回调 false
来表明认证错误而不是user。
return done(null, false);
可以提供额外的信息消息,以指示该失败的原因。适用于显示一个flash消息,提示用户再次尝试的。
return done(null, false, { message: 'Incorrect password.' });
最后,如果在验证凭据发生了异常(例如,如果数据库不可用),done
应该执执行error,这符合node的风格
return done(err);
注意,区别两种失败的原因是非常重要的。后者是服务器异常,其中 err
被设置为null
。 认证失败是正常情况,其中服务器状态正常的。 请确定 err
为 null
,并且使用最后一个参数传递一些附加信息。
通过这种委托的方式, verify callback 使 Passport 与数据库没有耦合。应用程序可以自由选择的用户信息是如何存储的,未经身份验证层施加的任何假设。
在基于 Connect 或 Express 的应用程序中,passport.initialize()
中间件是必须的启动 Passport.。如果应用程序使用持久的登录sessions, passport.session()
中间件也必须要启用。
app.configure(function() {
app.use(express.static('public'));
app.use(express.cookieParser());
app.use(express.bodyParser());
app.use(express.session({ secret: 'keyboard cat' }));
app.use(passport.initialize());
app.use(passport.session());
app.use(app.router);
});
注意,启动session是完全可选的,尽管在大多数程序中是推荐的。如果可用, express.session()
一定要在 passport.session()
之前,这样才能确保在登录会话以正确的顺序恢复。
在传统的web程序中,提供凭证来认证只是出现在登录请求中。如果认证成功,一个 session 就会被建立并保存一个cookie在用户浏览器。
每个后续请求将不包含凭据,而是用于标识会话的唯一的cookie。为了支持登录会话,Passport 会从session中序列化和反序列化 user
实例。
passport.serializeUser(function(user, done) {
done(null, user.id);
});
passport.deserializeUser(function(id, done) {
User.findById(id, function(err, user) {
done(err, user);
});
});
在这个例子中,只有用户ID被序列化至session中,并保持会话小中存储的数据量。当收到后续请求,这个ID是用来查找用户,这将恢复到 req.user
.
序列化和反序列化逻辑由应用程序提供,允许应用程序选择适当的数据库和/或对象映射,而不强加的身份验证层。