socket.io-clientでoriginが指定されたsocket.ioに接続する
2014年2月2日
つまりsocket.io-clientを利用したサーバー上のクライアントからのアクセス時には、Originを*:*にして、外部からのアクセス(通常のブラウザからのアクセス)時には、特定のHOST(Origin)のみを許可したい。
(Originで特定のHOSTに絞らない場合は、そもそも下記のような事はする必要はありませんので)
Client(socket.io-client)
まず、socket.io-clientからのアクセス時にヘッダー(下記ではx-dev-session)を追加。
(このヘッダーを持っているアクセス時のみOriginを*:*にします)
// 元のXMLHttpRequest
var Request = require('socket.io-client/node_modules/xmlhttprequest').XMLHttpRequest;
// ワンタイムなsession発行 -> KVSとかに保存
var session = 'xxxxxxxxxxxxxxxxxxxxx';
require('socket.io-client/node_modules/xmlhttprequest').XMLHttpRequest = function(){
Request.apply(this, arguments);
var open = this.open;
this.open = function() {
open.apply(this, arguments);
// ヘッダー追加
this.setRequestHeader('x-dev-session','xxxxxxxxxxxxxxxxxxxxx');
};
};
上記(local_header.js)を読み込んでserver.jsへアクセスするclient.js
// XMLHttpRequestをoverride
require('./local_header');
var socket = require('socket.io-client').connect("http://localhost:3000");
socket.on('connect',function(){
// 処理...
});
Server(socket.io)
特定のヘッダー(x-dev-session)のvalueがKVSにあるかチェックして、一致すればOriginを*:*に。
// 元のverifyOrigin
var localOrigin = require('socket.io').Manager.prototype.verifyOrigin;
require('socket.io').Manager.prototype.verifyOrigin = function() {
// KVSに保存したsessionチェック
if ( arguments[0].headers['x-dev-session'] == 'xxxxxxxxxxxxxxxxxxxxx' ) {
// KVSからsessionを消す処理
// ....
// originを*:*に
this.settings['origins'] = '*:*';
return true;
}
else {
// originを特定のドメインに
this.settings['origins'] = 'http://www.example.com:*';
}
return localOrigin.apply(this, arguments);
}
上記(local_manager.js)を読み込んだserver.jsを作成。
// verifyOriginをoverride
require('./local_manager');
var server = require('http').createServer();
var io = require('socket.io').listen(server);
io.on('connection', function(socket){
// 処理...
});
server.listen( 3000 );
// ...
これで、server.jsを起動すれば、外からのアクセスは特定のドメイン(www.example.com)のみに絞りつつ、client.jsからの内部的なアクセスもできるはずです。
他のやり方もありそうですが・・
誰かもっと簡単なやり方あったら教えてください。。
ホントは
- localhostのみ許可(もしくはlocal IPのみ許可)するとか?
- そもそも接続テスト以外に使いたい(crontabとかで内部的にイベントを発生させたい)場合は、StoreをRedisにして、pub/subでeventを起こすとか?
とかの方が綺麗かも。
そのうち試してみたいところ。