Carpe Diem

備忘録

Node.jsでOpenID認証

概要

OpenIDを用いてログイン認証(の一部)を実装します。
一部と言うのはDB含めたユーザデータの保持までは範囲外としてるためです。
またOAuthとの区別が付いていない人は、以下のリンクを参考にしてください。

非技術者のためのOAuth認証(?)とOpenIDの違い入門

OpenIDのメリット

  • ユーザが簡単にログイン出来る
  • ユーザがパスワードを覚えなくて済む
  • OAuthと違って共有される情報が制限されているので悪用の心配がない
  • OAuthと違ってGoogleDeveloperConsole、FacebookTwitterなどへのアプリ登録が不要

環境

  • Node.js 0.10.22
  • Express 4.0
  • passport 0.2.1

実装

事前準備

まずはスケルトンコードを生成します。

$ npm install express-generator -g
$ express

次にライブラリをpackage.jsonに追加します。passport, passport-googleというライブラリを使います。
またこのライブラリの仕組み上、passportというセッション内のオブジェクトにユーザ情報が入るため、セッションのライブラリexpress-sessionも必要です。

    "passport": "*",
    "passport-google": "*",
    "express-session": "*",

追加したらインストールします。

$ npm install

インストールしたら以下のコードをapp.jsに追記していきます。

ライブラリインポート

var passport = require('passport');
var session = require('express-session');
var GoogleStrategy = require('passport-google').Strategy;

app.use(passport.initialize());
app.use(passport.session());

callbackURLの設定と共有範囲の指定。

今回OpenID認証を通った後のコールバックURL、権限の範囲を

  • http://localhost:3000/auth/google/return
  • http://localhost:3000/

とします。

passport.use(new GoogleStrategy({
    returnURL: 'http://localhost:3000/auth/google/return',
    realm: 'http://localhost:3000/'
  },
  function(identifier, profile, done) {
    // identifierがopenID
    console.log('identifier: ', identifier);
    // profileがユーザー情報(例:profile.displayName)
    console.log('profile: ', profile);
    return done(null, profile);

    // サービス側のログインとしては、以下のようにサービス側でユーザの生成・確認を挟んでいく感じです。
//    User.findOrCreate({ openId: identifier }, function(err, user) {
//      done(err, user);
//    });
  }
));

// ユーザ情報を格納するpassportのシリアライズとデシリアライズ
passport.serializeUser(function(user, done){
    console.log('serializeUser: ', user);
    done(null, user);
});

passport.deserializeUser(function(obj, done){
    console.log('deserializeUser: '. obj);
    done(null, obj);
});

ルーティングの設定

/auth/googleにアクセスしたらOpenID認証が走るようにします。

app.get('/auth/google', passport.authenticate('google'));

app.get('/auth/google/return', passport.authenticate('google', { failureRedirect: '/login' }), function(req, res) {
    // Successful authentication, redirect home.
    res.redirect('/');
});

Viewの設定

./views/index.jadeにリンクを付けます。

extends layout

block content
  h1= title
  p Welcome to #{title}
  a(href="/auth/google") Sign In with Google

以上で設定は完了です。起動しましょう。

$ ./bin/www

動作確認

http://localhost:3000にアクセスしてみます。

f:id:quoll00:20141214160617p:plain

リンクをクリックします。

f:id:quoll00:20141214160959p:plain

ログインに使う自分のアカウントを選択します。

f:id:quoll00:20141214161034p:plain

権限の承認です。OpenIDの場合は

  • メールアドレス
  • プロフィール

が取得可能になってます。それ以外は共有されないので悪用に心配は余りありません。承認を押してください。

f:id:quoll00:20141214160617p:plain

認証が成功して/に戻ってきます。
ここでコンソールを確認するとレスポンスをログに出力していたので以下の情報が出力されます。

identifier:  https://www.google.com/accounts/o8/id?id=pu3chiichie1oong5ye0gohp3EiY2ugoo0noophi
profile:  { displayName: 'Foo Bar',
  emails: [ { value: 'cicatrice@gmail.com' } ],
  name: { familyName: 'Bar', givenName: 'Foo' }
serializeUser:  { displayName: 'Foo Bar',
  emails: [ { value: 'cicatrice@gmail.com' } ],
  name: { familyName: 'Bar', givenName: 'Foo' }

このように

  • ユーザのOpenID
  • Emailアドレス
  • プロフィール

が分かります。 ※上のIDは適当に生成したものに書き換えてます。
当然何度叩いても、その人のアカウントでログインすれば同じIDが返ってきます。
これを用いてユーザが本人であることがわかるので、サービス側で認証として利用ができるわけですね。

以上です。お疲れ様でした。

参考