2014年5月14日水曜日

RackアプリケーションでセッションIDを取得する

Webアプリの開発をしていると、現在のセッションIDを取得したくなることがあります。PHPですとsession_idというその名もズバリの関数が言語標準で用意されてたりしますが、Rubyだと言語標準にはないです。そもそもPHPと違ってセッションの仕組み自体言語標準ではなく、よく使われるのはRack::Session系のライブラリです。これは以前紹介したように幾つか種類があります。

しかしRack::Session系のライブラリで、現在のセッションID取得をどうやるかについてはドキュメントに分かりやすく書いておらず、探しにくかったです。(Rack::Session::Cookieの場合のみ、セッションのデータ自体にセッションIDが格納されるようですが、それ以外ではIDは入りません。)結局ソースコード読んで見つけました。結論から先に言いますと、

env['rack.session'].id

で取得できます。SinatraやPadrinoを使っている場合はもっと簡潔に

session.id

でOKです。(Sinatraにおけるsessionメソッドはrequest.sessionを呼びだします。Rack::Request#sessionは@env['rack.session']を返します。Sinatraにおけるenvメソッドはインスタンス変数@envへのアクセサですので、結局同じことになります。)

なお、今回(メインで)参照したソースコードはこれ↓。
https://github.com/rack/rack/blob/master/lib/rack/session/abstract/id.rb

上記URLにはRack::Session::Abstract::SessionHashとRack::Session::Abstract::IDの定義が書かれています。

ここにセッションIDを取得していそうなメソッドを発見。Rack::Session::Abstract::ID#current_session_id です。こいつを定義している部分で、

def current_session_id(env)
  env[ENV_SESSION_KEY].id
end

とやってますね。ちなみにRack::Session::Abstractモジュールの冒頭の方で

ENV_SESSION_KEY = 'rack.session’.freeze

と定義されてます。よって、env[‘rack.session’].idを呼べばセッションIDが取得できるとわかります。

なお、env[‘rack.session’]の中身は何かというと、Rack::Session::Abstract::ID#prepare_session で

env[ENV_SESSION_KEY] = session_class.new(self, env)

としてまして、ここでsession_classが何かといえば、Rack::Session::Abstract::ID#session_class の定義が

def session_class
  SessionHash
end

となってます。要するに、env[‘rack.session’]に入っているのはRack::Session::Abstract::SessionHashのインスタンスなのでした。ちなみに、アプリケーション中で p env[‘rack.session’] などとするとハッシュに見える結果が返ってきますが、これは inspect メソッドが定義されているからです。

def inspect
  if loaded?
    @data.inspect
  else
    "#<#{self.class}:0x#{self.object_id.to_s(16)} not yet loaded>"
  end
end

インスタンス変数@data はハッシュですので、 inspect した結果がハッシュになるのですね。(Kernel.#p は内部的にObject#inspect を呼びます。)

ついでに、Rack::Session::Abstract::SessionHash#id を見てみますと

def id
  return @id if @loaded or instance_variable_defined?(:@id)
  @id = @store.send(:extract_session_id, @env)
end

となってまして、セッションIDはRack::Session::Abstract::SessionHashのインスタンス変数@idに保持されていることがわかります。

※この記事について指摘・意見・提案・感想などありましたら下のコメント欄にどうぞ。

※2014/05/22更新:Rack::Session::Cookieの場合のみ、セッションのデータ自体にセッションIDが格納される点について追記。
※2014/06/04更新:SinatraやPadrinoの場合のより簡潔な書き方を追記。

0 件のコメント:

コメントを投稿