同样,本文的大部分内容都是从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}); } );
写了这么多,发现还是直接看源代码来的明白,这里只为了记录: