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を起こすとか?
とかの方が綺麗かも。
そのうち試してみたいところ。