同样,本文的大部分内容都是从Danial Khosravi上学习的。经过一番折腾之后,我发现挺不错的。唯一一个问题,就是国内需要「翻墙」,这里不得不使用 GitHub 来演示代码。
同理,介绍下这篇文章的目录索引:
什么是 PassportJs ?
PassportJs是一个 NodeJS 的中间件模块。非常灵活并且模块化,使用它可以轻松地让Facebook、Twitter或者其他社交网站的用户登录到你的应用。
一、如何安装 PassportJS 到你的应用?
使用npm来安装 PassportJS
$ npm install passport
因为这里需要让 GitHub 的用户登录到你的应用,所以需要安装 PassportJS 的插件,还有一个本地插件也是需要安装下来。
$ npm install passport-local $ npm install passport-github
二、添加 PassportJS 的中间件
和上一篇文章介绍的一样,除了普通的依赖之外,还需要添加 PassportJs 的中间件到应用中来:
app.use(express.cookieParser());
app.use(express.bodyParser());
app.use(express.session({ secret: 'SECRET' }));
//下面两条就是passportjs的中间件引用
app.use(passport.initialize());
app.use(passport.session());
三、数据库和模块
同样,这里使用MongoDB来作为数据库。所以:
- 需要通过
mongod来启动 mongo; - 创建应用并链接数据库的方法:
mongoose.connect("mongodb://localhost/myapp"); - 设置本地用户表:
var LocalUserSchema = new mongoose.Schema({
username: String,
salt: String,
hash: String
});
var Users = mongoose.model('userauths', localUserSchema);
我们需要在用户表里面创建一个字段,用于存放来自 GitHub 用户的信息。
var GithubUserSchema = new mongoose.Schema({
fbId: String,
email: { type : String , lowercase : true},
name : String
});
var FbUsers = mongoose.model('fbs',GithubUserSchema);
四、设置和策略
初始化passport,以便于我们在应用中使用。
1.本地策略
passport.use(new LocalStrategy(function(username, password,done){
Users.findOne({ username : username},function(err,user){
if(err) { return done(err); }
if(!user){
return done(null, false, { message: 'Incorrect username.' });
}
hash( password, user.salt, function (err, hash) {
if (err) { return done(err); }
if (hash == user.hash) return done(null, user);
done(null, false, { message: 'Incorrect password.' });
});
});
}));
2.GitHub 用户策略
首先需要到这里申请一个 GitHub 的应用,获取clientID和clientSecret,并确定好 GitHub 授权之后的callbackURL。
passport.use(new GithubStrategy({
clientID: "YOUR ID",
clientSecret: "YOUR CODE",
callbackURL: "http://localhost:3000/auth/github/callback"
},function(accessToken, refreshToken, profile, done) {
FbUsers.findOne({fbId : profile.id}, function(err, oldUser){
if(oldUser){
done(null,oldUser);
}else{
var newUser = new FbUsers({
fbId : profile.id ,
email : profile.emails[0].value,
name : profile.displayName
}).save(function(err,newUser){
if(err) throw err;
done(null, newUser);
});
}
});
}));
另外一件重要的事情,是设置连载。这样就能在用户的浏览器中建立一个会话的cookie。
passport.serializeUser(function(user, done) {
done(null, user.id);
});
passport.deserializeUser(function(id, done) {
FbUsers.findById(id,function(err,user){
if(err) done(err);
if(user){
done(null,user);
}else{
Users.findById(id, function(err,user){
if(err) done(err);
done(null,user);
});
}
});
});
五、辅助功能函数
就如同前一篇文章一样,需要一些辅助的函数来处理用户登录过程中的问题。这里同样需要。
- authenticatedOrNot 用于判断用户是否已经登录了。
- userExist 用于判断用户是否存在。
function authenticatedOrNot(req, res, next){
if(req.isAuthenticated()){
next();
}else{
res.redirect("/login");
}
}
function userExist(req, res, next) {
Users.count({
username: req.body.username
}, function (err, count) {
if (count === 0) {
next();
} else {
// req.session.error = "User Exist"
res.redirect("/singup");
}
});
}
六、路由器
主要需要新增两个地址,一个是请求 GitHub 登录的,一个是 GitHub 登录之后的 callback。
app.get("/auth/github", passport.authenticate("github",{ scope : "email"}));
app.get("/auth/github/callback",
passport.authenticate("github",{ failureRedirect: '/login'}),
function(req,res){
res.render("loggedin", {user : req.user});
}
);
写了这么多,发现还是直接看源代码来的明白,这里只为了记录: