進(jìn)階學(xué)習(xí)

2024-12-03 17:46 更新

雖然基本用法已經(jīng)能覆蓋一般需求了,但是還是有各種edge case的存在。passport也提供了一些擴(kuò)展性的功能來應(yīng)對不同的場景。下面就來講一下。

驗(yàn)證多個條件

有的時候,在登錄時不但需要驗(yàn)證用戶名和密碼,還需要驗(yàn)證一個附加條件,比如Discuz!論壇程序提供的功能:

20141116005335

這種情況passport也是支持的。

在配置策略的時候,Strategy接受一個options參數(shù),它包含一個passReqToCallback項(xiàng),默認(rèn)為false,設(shè)置為true時可以將整個req傳遞給回調(diào)函數(shù),這樣在回調(diào)里就可以驗(yàn)證req中帶的所有條件了。示例代碼如下:

passport.use(new LocalStrategy(
  {passReqToCallback: true},
  function(req, username, password, done) {
    // now you can check any req.body.xxx
  }
));

這個方法在OAuth驗(yàn)證中也是支持的。

使用多種驗(yàn)證策略/匿名登錄驗(yàn)證

最常見的case是貼吧,我們支持已登錄的用戶發(fā)帖,但是對匿名用戶也支持發(fā)帖回帖,但對它們屏蔽了一些高級用法。

這里需要用到匿名驗(yàn)證策略passport-anonymous,它的使用非常簡單,只需要聲明一句就行了:

passport.use(new AnonymousStrategy());

要實(shí)現(xiàn)多種驗(yàn)證策略,可如下配置:

var passport = require('passport')
  , LocalStrategy = require('passport-local').Strategy
  , AnonymousStrategy = require('passport-anonymous').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: '用戶名不存在.' });
      }
      if (!user.validPassword(password)) {
        return done(null, false, { message: '密碼不匹配.' });
      }
      return done(null, user);
    });
  }
));
//匿名登錄認(rèn)證作為本地認(rèn)證的fallback
passport.use(new AnonymousStrategy());

...

app.get('/',
  passport.authenticate(['local', 'anonymous'], { session: false }),
  function(req, res){
    if (req.user) {
      res.json({ msg: "用戶已登錄"});
    } else {
      res.json({ msg: "用戶以匿名方式登錄"});
    }
  });

我們可以看到使用多種驗(yàn)證策略時,可使用數(shù)組來將策略名稱作為參數(shù)傳給authenticate方法。

匿名驗(yàn)證是作為local驗(yàn)證的fallback而存在,當(dāng)local驗(yàn)證不滿足時會調(diào)用后面的驗(yàn)證方法。

理論上講這種調(diào)用方法也可用于其它驗(yàn)證,但不鼓勵這么做,它會讓用戶系統(tǒng)變得極為復(fù)雜難以維護(hù)。、

最后注意:使用匿名驗(yàn)證時需要將session設(shè)為false,不將匿名用戶信息存儲到session中。

游客登錄驗(yàn)證

還有一種使用場景是將所有的匿名用戶都視為游客,這樣你可以通過用戶管理頁面來操作所有的游客的信息。

你可以通過passport-anonymous來實(shí)現(xiàn)這一點(diǎn),將所有的匿名用戶都賦予同一個用戶ID,但還有一個passport插件來專門做這件事,那就是passport-dummy,它的使用方法如下:

var passport = require('passport')
  , DummyStrategy = require('passport-dummy').Strategy;

// 設(shè)置部分
passport.use(new DummyStrategy(
  function(done) {
    return done(null, {username: 'dummy'});
  }
));

// 路由部分
app.post('/login', 
  passport.authenticate('dummy', { failureRedirect: '/login' }),
  function(req, res) {
    res.redirect('/');
  });

實(shí)際使用中經(jīng)常需要與其他驗(yàn)證方法結(jié)合起來,比如在上面的多種驗(yàn)證策略中代替匿名登錄驗(yàn)證。

在其他Web框架中使用passport

這里要明白,passport只是做登錄驗(yàn)證的,只是操作session,甚至連驗(yàn)證都是用戶自己完成,它本身是個很獨(dú)立的模塊,但是由于其使用了connect中的一些方法,因此與connect有些耦合。

因此一般的connect-style 的web框架passport都能直接使用,無需適配。

那么要在其它web框架中如Hapi中能使用passport嗎?

回答是理論上能,但不建議直接這么做。一般這樣的框架也應(yīng)該都有自己的驗(yàn)證模塊或插件,如果實(shí)在不能滿足需求,非要用passport,這里提供一下思路:首先要支持session,然后構(gòu)造類似express中的req和res,起碼要支持res.session各種操作,以及將http request賦值為req。

這里有Hapi框架使用passport的教程,可以看到非常麻煩, 它本身已經(jīng)有hapi-auth-cookie和bell模塊用于驗(yàn)證,所以不必執(zhí)著于使用passport。

在RESTful API中使用passport

RESTful API的驗(yàn)證分為兩種情況。一種是面向自己app的用戶,其驗(yàn)證和http驗(yàn)證一樣。另一種是向第三方提供的API,這種情況下可能每次連接都需要驗(yàn)證,反而不需要用到session了。passport也支持這樣的做法。

想要每次連接都進(jìn)行驗(yàn)證,只需將authenticate方法作為中間件添加到需要驗(yàn)證的URL里,然后將session設(shè)為false:

app.get('/api/users/me',
  passport.authenticate('basic', { session: false }),
  function(req, res) {
    res.json({ id: req.user.id, username: req.user.username });
  });

這樣每次連接都需要經(jīng)過authenticate,并且不會被記錄在session里。

制作passport插件

passport以插件的形式支持了很多第三方網(wǎng)站和服務(wù)的OAuth驗(yàn)證,但并不是所有的,如果你需要在app中用到第三方的服務(wù),但它們沒有對應(yīng)的passport插件,你可以用通用的OAuth或其他驗(yàn)證方法來進(jìn)行驗(yàn)證,也可以將它們封裝成passport-x插件。

制作passport插件并不困難,因?yàn)樗皇菍Σ呗缘呐渲貌糠诌M(jìn)行了一些封裝而已,你可以將一個已有的passport插件稍微修改即可。

比如要制作一個OAuth2.0的passport插件,你可以以passport-github為模板,甚至只需要修改它的strategy.js,步驟總結(jié)如下:

  1. 將所有帶github.com的地址修改為對應(yīng)的地址;
  2. 將github、passport-github修改為你需要的服務(wù)的名稱。

沒錯,就是這么簡單!

如果僅僅為自己使用,上面的步驟已經(jīng)足夠,但你還可以將它們分享出來給別人使用,這需要額外的步驟:

  1. 修改example/login,以及readme.md,并測試;
  2. 將你的插件發(fā)布到Github和npm上;
  3. 給passport作者Jared Hanson發(fā)郵件,或者到passport的Github頁面上發(fā)issue,將插件添加到provider list上。

現(xiàn)在你也是passport的貢獻(xiàn)者了!~

更多的驗(yàn)證方案

上面我們只是講到了local驗(yàn)證和OAuth驗(yàn)證,以及提到了一下anonymous驗(yàn)證,但實(shí)際上passport支持的驗(yàn)證方法不止這幾種,具體支持的驗(yàn)證方案可以參見這個頁面。

在多數(shù)時候,我們只需要引入這些實(shí)現(xiàn)方案,就可以進(jìn)行驗(yàn)證。

這里的驗(yàn)證方案在我們想向第三方app提供RESTful API時非常有用。

推薦項(xiàng)目

一些學(xué)習(xí)passport具體實(shí)現(xiàn)的Nodejs項(xiàng)目。

  • Hackathon Starter:實(shí)現(xiàn)了超過10個第三方服務(wù)OAuth登錄驗(yàn)證。
  • nodeclub:實(shí)現(xiàn)Github OAuth驗(yàn)證。

參考鏈接

以上內(nèi)容是否對您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號
微信公眾號

編程獅公眾號