17
14

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

Express4 + Passport で Google アカウントでログインしたセッションを Socket.IO から参照する

Last updated at Posted at 2015-07-29

ほどよいサンプルがなかったので作った。

Express4 のインストール

WebStorm 10 のテンプレートで「Node.js Express App」を選んで自動的に作成。
Template は Jade。

モジュールはこんな感じ

package.json
{
  "name": "NodeExpPassportOAuth2_SocketIO",
  "version": "0.0.0",
  "private": true,
  "scripts": {
    "start": "node ./bin/www"
  },
  "dependencies": {
    "body-parser": "~1.12.4",
    "cookie-parser": "~1.3.5",
    "debug": "~2.2.0",
    "express": "~4.12.4",
    "jade": "~1.9.2",
    "morgan": "~1.5.3",
    "serve-favicon": "~2.2.1",
    "passport": "^0.2.2",
    "express-session": "^1.11.2",
    "mongoose": "^4.0.4",
    "passport-google-oauth": "^0.2.0",
    "socket.io": "^1.3.5",
    "cookie": "^0.1.3",
    "passport.socketio": "^3.5.1",
    "connect-mongo": "^0.8.1"
  },
  "main": "app.js",
  "devDependencies": {},
  "author": "",
  "license": "ISC"
}

このような。

MongoDB を準備する

いろいろ保存しておきたいので MongoDB を使う。
データのモデルは models/user.js に作る

modeles/user.js
var mongoose = require('mongoose');
var Schema = mongoose.Schema;

var User = new Schema({
    // User ID (google account id)
    uid: {
        type: String,
        unique: true
    },
    // display name
    displayName: {
        type: String
    },
    // E-mail
    email: {
        type: String
    },
    // icon
    icon: {
        type: String
    }
}, {
    // define this collection's name explicitly
    collection: "users"
});

module.exports = mongoose.model('User', User);

app.js

var User = require('./models/user.js');
mongoose.connect('mongodb://localhost/passport-google-oauth-example');
var mongoose = require('mongoose');

Passport で Google アカウントと連携する

passport と passport-google-oauth を使う。

app.js

var passport = require('passport');
var GoogleStrategy = require('passport-google-oauth').OAuth2Strategy;

// session serializer
passport.serializeUser(function(req, uid, done) {
  done(null, uid);
});

// session deserializer
passport.deserializeUser(function(req, uid, done) {
  // MongoDB からユーザーを取ってくる
  User.findOne({
    uid: uid
  }, function(err, user) {
    done(null, user);
  });
});

// Google アカウントで OAuth2 接続
passport.use(new GoogleStrategy({
	  clientID: GOOGLE_CLIENT_ID, //ご自分のやつをどうぞ
	  clientSecret: GOOGLE_CLIENT_SECRET, //ご自分のやつをどうぞ
	  callbackURL: CALLBACK_URL //ご自分のやつをどうぞ
	}, 
	function(accessToken, refreshToken, profile, done) {
	  proce	ss.nextTick(function() {
		//認証情報を DB に保存
	    var uid = profile.id;
	    var displayName = profile.displayName;
	    var email = profile.emails[0].value;
	    var icon = profile.photos[0].value;

	    User.findOneAndUpdate({
	      uid: uid
	    }, {
	      $set: {
	        uid: uid,
	        displayName: displayName,
	        email: email,
	        icon:icon
	      }
	    }, {
	      upsert: true
	    }, function(err, user) {
	      return done(null, uid);
	    });
	  }
	);

}));

SessionStore に MongoDB を使う

connect-mongo が良いらしい。

app.js
var MongoStore = require('connect-mongo')(session); //Express のセッションを引数に渡す
var sessionStore = new MongoStore({ mongooseConnection: mongoose.connection }); 

//Express のセッションを設定
app.use(session({
    key: 'express.sid', //socket.io から参照する際にキーとして使ってるっぽい
    secret: "session_secret",
    saveUninitialized: true,
    store: sessionStore, //passport-socketio のセッションストアに使えるやつじゃないとエラー出る 
    resave: false
}));
app.use(passport.initialize());
app.use(passport.session());

router まわりを設定する

routes/index.js

// Google アカウントでログインするためのリンク
router.get('/auth/google', passport.authenticate('google', {
      scope: ['https://www.googleapis.com/auth/plus.login', "email", "profile"]
    }),
    function(req, res) {} // this never gets called
);

// Google OAuth のコールバックを設定
router.get('/oauth2callback', passport.authenticate('google', {
  successRedirect: '/',
  failureRedirect: '/login'
}));


/* logout */
router.get('/logout', function(req, res) {
  req.logout();
  res.redirect('/');
});

あとは Socket IO から諸々設定するだけだ!


var io = require('socket.io')(server);
var passportSocketIo = require("passport.socketio");

//Passport のセッションを SocketIO からも使えるように
io.use(passportSocketIo.authorize({
    passport : passport,
    cookieParser: require('cookie-parser'),
    key:          'express.sid',
    secret:       'session_secret',
    store:        sessionStore, //さっきの sessionStore 渡す
    success:      onAuthorizeSuccess,
    fail:         onAuthorizeFail
}));


// セッションのAuthorize 成功

function onAuthorizeSuccess(data, accept){
    console.log('successful connection to socket.io');
    accept(null, true);

}

//セッションのAuthorizeしっぱいしっぱい
function onAuthorizeFail(data, message, error, accept){
    if(error) {
        throw new Error(message);
    }
    console.log('failed connection to socket.io:', message);
    accept(null, false);
}

//接続があったら
io.on('connection', function(socket) {
    console.log('socket-io connect');

    var user = socket.request.user; //これでユーザーを参照できる
    if(user){
        console.log("session data : ", user);
    }
});

HTML側から

Google アカウントでログインしたあとに、普通に SocketIO に connect してください。


var socket = io.connect();

ややこしいところ

  • Express 3 と 4 で Passport まわりの挙動がいちいち違う。
  • Google アカウントの認証モジュールがたくさんあって困る。 しかも先日、 OAuth2しかつながらなくなったので使い物にならないものも多い。 npm のサイトで DL 数の多いやつを選ぶとよいかも。
  • 同様に、Socket IO と Passport を繋ぐモジュールがたくさんあって困る。
  • Passport の sessionStore では動くけど Socket.IO の sessionStore に指定できないやつが結構ある。
    このへん https://github.com/senchalabs/connect/wiki#session-stores を見るといいらしい。
17
14
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
17
14

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?