Node.jsでPassportを使ってFacebook認証する

  • 投稿日:
  • by

Node.jsで困るのはある機能を満たすためにどのパッケージを使っていいか分からないことです。発展途上ということで納得しましょう。発展途上というか生態系。

今回、Facebook認証をするためのモジュールを探しました。 stackoverflowで色々比較コメントがあり、それらやREADMEを参考にしました。

connect-authというのは名前もいいし、それなりのStar数もあります。シンプルでよさそうなのですが、よく使い方が分かりません。人気があるのは後発のeveryauthのようです。しかし、ドキュメントを読んでみてもどうもピンときません。なにか、感性が合わないような気がしました。

そこで、Passportを試すことにしました。 http://passportjs.org/guide/facebook/にドキュメントがあります。everyauthと比較するとコーディング量は多いかもしれませんが、なんとなくこちらの方が合う気がします。それでも、accessTokenが欲しいだけの場合は、userオブジェクトなんて作らなくてもいいのですけど。これはeveryauthも同じ(?)なので我慢するとします。

簡単に今使ってみた方法を紹介します。

まずは、ライブラリのロードです。サンプルをコピペしただけです。

var passport = require('passport');
var FacebookStrategy = require('passport-facebook').Strategy;

続いて、FacebookStrategyの設定です。accessTokenだけ欲しかったので、それをuserオブジェクトにします。必要であれば、profileとかも入れればよいでしょう。userオブジェクトは、req.userで参照できるので、accessTokenはreq.user.accessTokenになります。

passport.use(new FacebookStrategy({
  clientID: process.env.FACEBOOK_APP_ID,
  clientSecret: process.env.FACEBOOK_SECRET,
  callbackURL: process.env.CALLBACK_URL
}, function(accessToken, refreshToken, profile, done) {
  done(null, {
    accessToken: accessToken
  });
}));

サンプルにあったシリアライザも入れておきます。これは書かなくてもよさそうと思ったのですが、ソースみてもデフォルトがあるように見えず、念のためいれておきます。

passport.serializeUser(function(user, done) {
  done(null, user);
});
passport.deserializeUser(function(obj, done) {
  done(null, obj);
});

強制的にログインさせるmiddlewareです。一度、ログインを促すページを表示するほうが親切かもしれません。

function ensureAuthenticated(req, res, next) {
  if (req.isAuthenticated()) {
    next();
  } else if (req.url.lastIndexOf('/auth/', 0) >= 0) {
    next();
  } else {
    res.redirect('/auth/facebook');
  }
}

expressの設定です。セッションを使うのでその設定が必要です。

var app = express();
app.use(express.cookieParser());
app.use(express.session({ secret: 'foobar' }));
app.use(passport.initialize());
app.use(passport.session());
app.use(ensureAuthenticated);

最後に、expressのルートの設定をします。failureRedirectは暫定です。

app.get('/auth/facebook', passport.authenticate('facebook'));
app.get('/auth/facebook/callback', passport.authenticate('facebook', {
  successRedirect: '/',
  failureRedirect: '/auth/loginfailed'
}));
app.get('/auth/loginfailed', function(req, res) {
  res.send('login failed');
});

以上、こんな感じで使うようです。/auth/facebookのようなルートを設定しなければならないのを面倒と考えるか、分かりやすいと考えるかが、Passportを受け入れられるかの境目かもしれません。