2014年5月2日金曜日

PadrinoでRack::Session::Poolを使う方法

先日、Rack::Session::PoolとRack::Session::Cookieの違いについて書きましたけれども、Padrinoで実際にRack::Session::Poolを使う設定をしてみたので、メモしておきます。

Padrinoでは、デフォルトではapp/app.rbに

enable :sessions

と記述があり、セッション管理が有効になっています。PadrinoのベースであるSinatraは上記の記述がある場合にRack::Session::Cookieをオプション無しで呼び出します。そのためここではCookieの有効期限などの細かい設定はできません。

細かい設定をしたい場合は、enable :sessions の代わりに Rack::Session::Cookie を直接使うように、Sinatraの公式ドキュメントにも書いてあります。だったら、同様にRack::Session::Cookie ではなくRack::Session::Poolを直接呼び出せば大丈夫のような気がします。

ところがPadrinoだと、プロジェクトジェネレータで生成されたアプリケーションのapp/app.rbにおいて、

disable :sessions
use Rack::Session::Pool

などとやろうとすると下記のようなエラーになってしまいます。ちなみにこれはRack::Session::Cookie を使おうとしても同様のエラーになります。

you need to set up a session middleware *before* Rack::Protection::AuthenticityToken (RuntimeError)

これは、Padrinoのデフォルトで Rack::Protection 関係のオプションが有効になっているためです。config/apps.rbの次のような記述が該当します。

Padrino.configure_apps do
  # enable :sessions
  set :session_secret, 'sessionseacretkeystring12345567890abcdef'
  set :protection, :except => :path_traversal
  set :protect_from_csrf, true
end

なので、一旦 Rack::Protection 関係のオプションを無効にし、Rack::Session::Poolを直接呼び出した後にRack::Protectionを直接呼び出します(Rack::Protection 関係のオプションを改めて有効にするとエラーになってしまいます)。app/app.rbのenable :sessionsをコメントアウトし、次の記述を追加します。disable :sessionsは不要かもしれませんが念のため入れてます。

set :protection, false
set :protect_from_csrf, false
disable :sessions
use Rack::Session::Pool, :key => 'rack.session', :path => '/', :expire_after => nil
use Rack::Protection
use Rack::Protection::AuthenticityToken, :authenticity_param => '_csrf_token'

これでエラーが消えました。セッションも、Cookieを確認すると、今までBase64でエンコードされた非常に長い文字列(おそらく暗号化したキー・バリューの組み合わせがセッションIDとともに入っている)だったのが、セッションIDのみらしき文字列に変化しています。上記コードでは有効期限を設定していませんが、指定すればCookieに反映されることは確認できました。なお、 Rack::Protection 関係がきちんど動作しているかどうかは未検証ですのでご注意ください。Rack::Protection::AuthenticityTokenも動作してるのを確認しました。

※2014/05/02 Rack::Protection::AuthenticityTokenの動作を確認したことを追記、コードの use Rack::Protection::AuthenticityToken にトークンのパラメータ名を指定する引数を追加

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

0 件のコメント:

コメントを投稿