鍍金池/ 教程/ HTML/ 番外篇之——使用 Passport
第9章 增加標(biāo)簽和標(biāo)簽頁面
番外篇之——使用 Mongoose
番外篇之——使用 Async
第4章 實現(xiàn)用戶頁面和文章頁面
第12章 增加友情鏈接
第14章 增加頭像
第7章 實現(xiàn)分頁功能
第5章 增加編輯與刪除功能
第11章 增加文章檢索功能
第3章 增加文件上傳功能
番外篇之——部署到 Heroku
第2章 使用 Markdown
第13章 增加404頁面
第16章 增加日志功能
第1章 一個簡單的博客
番外篇之——使用 Handlebars
第10章 增加pv統(tǒng)計和留言統(tǒng)計
番外篇之——使用 Passport
第15章 增加轉(zhuǎn)載功能和轉(zhuǎn)載統(tǒng)計
第8章 增加存檔頁面
番外篇之——使用 generic pool
番外篇之——使用 _id 查詢
番外篇之——使用 Disqus
番外篇之——使用 KindEditor
第6章 實現(xiàn)留言功能

番外篇之——使用 Passport

前面我們自己寫了一個簡單的登陸認(rèn)證系統(tǒng),即用戶在登陸時,通過輸入事先注冊的用戶名和密碼,服務(wù)器確認(rèn)用戶的身份后,從而獲得操作權(quán)限。這也是最傳統(tǒng)的登陸認(rèn)證方式。

隨著互聯(lián)網(wǎng)的不斷開放與發(fā)展,又出現(xiàn)了一種新的登陸認(rèn)證方式——第三方登陸認(rèn)證,即我們常說的oAuth/oAuth2.0。

什么是 oAuth?

OAUTH協(xié)議為用戶資源的授權(quán)提供了一個安全的、開放而又簡易的標(biāo)準(zhǔn)。與以往的授權(quán)方式不同之處是OAUTH的授權(quán)不會使第三方觸及到用戶的帳號信息(如用戶名與密碼),即第三方無需使用用戶的用戶名與密碼就可以申請獲得該用戶資源的授權(quán),因此OAUTH是安全的。

什么是 Passport?

Passport是一個基于Node.js的認(rèn)證中間件。極其靈活并且模塊化,Passport可以很容易地跟任意基于Express的Web應(yīng)用結(jié)合使用。 現(xiàn)在我們來修改代碼,使得我們的博客既支持本地登陸又支持使用 GitHub 賬戶登錄。

首先,登錄 GitHub ,點擊右上角的 Account settings ,然后點擊左側(cè)的 Applications ,然后點擊右上角的 Register new application 創(chuàng)建一個 GitHub 應(yīng)用。

創(chuàng)建成功后如下圖所示:

http://wiki.jikexueyuan.com/project/express-mongodb-setup-blog/images/7.1.jpeg" alt="" />

稍后我們將會用到 Client ID 、Client Secret 和 Authorization callback URL。

打開 package.json ,添加 passport 和 passport-github 模塊:

"passport": "*",
"passport-github": "*"

并 npm install 安裝這兩個模塊。

至此,準(zhǔn)備工作都已完成,接下來我們修改代碼支持使用 GitHub 賬戶登錄。

首先,添加使用 GitHub 登陸的鏈接。打開 login.ejs,在:

<%- include footer %>

上一行添加如下代碼:

<a href="/login/github">使用 GitHub 登錄</a>

然后打開 app.js ,在 var app = express(); 下添加如下代碼:

var passport = require('passport')
    , GithubStrategy = require('passport-github').Strategy;
在 app.use(app.router); 上添加一行代碼:

app.use(passport.initialize());//初始化 Passport

在 if ('development' == app.get('env')) 上添加如下代碼:

passport.use(new GithubStrategy({
  clientID: "xxx",
  clientSecret: "xxx",
  callbackURL: "xxx"
}, function(accessToken, refreshToken, profile, done) {
  done(null, profile);
}));

注意:將 clientID、clientSecret 和 callbackURL 分別替換為剛才創(chuàng)建 GitHub 應(yīng)用得到的信息。

以上代碼的意思是:我們定義了一個 Passport 策略,并嘗試從 GitHub 獲得授權(quán),從 GitHub 登陸并授權(quán)成功后以跳轉(zhuǎn)到 callbackURL 并以 JSON 形式返回用戶的一些相關(guān)信息,并將這些信息存儲在 req.user 中。

打開 index.js ,在上方添加一行代碼:

var passport = require('passport');

并在 app.get('/login') 后添加如下代碼:

app.get("/login/github", passport.authenticate("github", {session: false}));
app.get("/login/github/callback", passport.authenticate("github", {
  session: false,
  failureRedirect: '/login',
  successFlash: '登陸成功!'
}), function (req, res) {
  req.session.user = {name: req.user.username, head: "https://gravatar.com/avatar/" + req.user._json.gravatar_id + "?s=48"};
  res.redirect('/');
});

這里我們可以直接使用 Express 的 session 功能,所以禁掉 Passport 的 session 功能,前面提到過 Passport 默認(rèn)會將取得的用戶信息存儲在 req.user 中而不是 req.session.user,為了保持兼容,所以我們提取并序列化有用的數(shù)據(jù)保存到 req.session.user 中。

至此,我們的博客也支持 GitHub 登錄了,是不是很簡單?目前還存在三個問題:

  1. GitHub 用戶名和本地數(shù)據(jù)庫用戶名重名的問題。
  2. 不能訪問使用 GitHub 賬戶登錄的用戶的用戶頁。
  3. 無法從 GitHub 獲得用戶的郵箱。

第一個問題的簡單粗暴的解決方法是當(dāng)用戶以 GitHub 賬戶登錄時,把獲取的用戶名到本地數(shù)據(jù)庫查一下,若存在則禁止登錄,若不存在則允許登陸。

第二個問題修改一下代碼即可解決,刪除 index.js 中 app.get('/u/:name') 內(nèi)的那層判斷數(shù)據(jù)庫中是否存在該用戶名的函數(shù)即可。

第三個問題暫時無法解決,因為 GitHub 返回的信息中并不包含有效的用戶郵箱。