RoR3でRESTfulAPIを記述しています。アプリケーションで「Set-Cookieヘッダー」を送信しないようにする必要があります(クライアントはauth_tokenパラメーターを使用して認証しています)。
session :off
とreset_session
を使おうとしましたが、意味がありません。認証フレームワークとしてdevise
を使用しています。
これが私のApplicationControllerです
class ApplicationController < ActionController::Base
before_filter :reset_session #, :unless => :session_required?
session :off #, :unless => :session_required?
skip_before_filter :verify_authenticity_token
before_filter :access_control_headers!
def options
render :text => ""
end
private
def access_control_headers!
response.headers["Access-Control-Allow-Origin"] = "*"
response.headers["Access-Control-Allow-Methods"] = "GET, POST, PUT, DELETE, OPTIONS"
response.headers["Access-Control-Allow-Credentials"] = "true"
response.headers["Access-Control-Allow-Headers"] = "Content-type"
end
def session_required?
!(params[:format] == 'xml' or params[:format] == 'json')
end
end
Johnの回答に対するコメントで述べられているように、セッションをクリアしても、セッションCookieの送信が妨げられることはありません。 Cookieの送信を完全に削除したい場合は、Rackミドルウェアを使用する必要があります。
class CookieFilter
def initialize(app)
@app = app
end
def call(env)
status, headers, body = @app.call(env)
# use only one of the next two lines
# this will remove ALL cookies from the response
headers.delete 'Set-Cookie'
# this will remove just your session cookie
Rack::Utils.delete_cookie_header!(headers, '_app-name_session')
[status, headers, body]
end
end
次の本体で初期化子を作成して使用します。
Rails.application.config.middleware.insert_before ::ActionDispatch::Cookies, ::CookieFilter
Cookieフィルターがアプリケーションスタックトレースに含まれるのを防ぐために、場合によっては完全に混乱する可能性があります。バックトレースでCookieフィルターを無音にすることをお勧めします(lib/cookie_filter.rb
に配置したと仮定)。
Rails.backtrace_cleaner.add_silencer { |line| line.start_with? "lib/cookie_filter.rb" }
組み込みオプションを使用します。
env['rack.session.options'][:skip] = true
または同等のもの
request.session_options[:skip] = true
ここでそのドキュメントを見つけることができます http://doc.rubyists.com/rack/Rack/Session/Abstract/ID.html
彼らがいつDeviseに追加したかはわかりませんが、auth_tokenを使用するときにセッションCookieの送信を無効にできる構成があるようです。
# By default Devise will store the user in session. You can skip storage for
# :http_auth and :token_auth by adding those symbols to the array below.
# Notice that if you are skipping storage for all authentication paths, you
# may want to disable generating routes to Devise's sessions controller by
# passing :skip => :sessions to `devise_for` in your config/routes.rb
config.skip_session_storage = [:http_auth, :token_auth]
それはうまく機能します。私が抱えていた唯一の問題は、トークンを生成/取得するために、 token_controller に最初のリクエストを送信できる必要があるということでした。つまりPOST /api/v1/tokens.json
、残念ながら、そのリクエストに対してセッションCookieが返されます。
とにかく、RyanAhearnが上で書いたCookieFilter
イニシャライザーを実装することになりました。
また、私のアプリにはWebフロントエンドとJSON APIの両方があるため、JSONAPIのCookieのみをフィルタリングしたかったのです。そこで、CookieFilter
クラスを変更して、最初にAPIに属するリクエストを確認しました。
if env['PATH_INFO'].match(/^\/api/)
Rack::Utils.delete_cookie_header!(headers, '_myapp_session')
end
それを行うためのより良い方法があるかどうかわからない...
別の解決策:Cookieを回避するコントローラーで、次を追加します。
after_filter :skip_set_cookies_header
def skip_set_cookies_header
request.session_options = {}
end
Apiコントローラーのセットがある場合は、これをapi_controllerクラスに設定し、他のコントローラーにapi_controllerを継承させます。
セッションoptsが空であるため、これはSet-Cookieヘッダーの設定をスキップします。
デフォルトのCookieSessionStoreは、セッションに何かが追加されない限り、「Set-Cookie」ヘッダーを送信しません。スタック内の何かがセッションに書き込んでいますか? (おそらくDeviseです)
session :off
は非推奨になりました:
def session(*args)
ActiveSupport::Deprecation.warn(
"Disabling sessions for a single controller has been deprecated. " +
"Sessions are now lazy loaded. So if you don't access them, " +
"consider them off. You can still modify the session cookie " +
"options with request.session_options.", caller)
end
スタック内の何かがセッション情報を設定している場合は、次のようにsession.clear
を使用してクリアできます。
after_filter :clear_session
def clear_session
session.clear
end
これにより、Set-Cookieヘッダーが送信されなくなります
Johnの回答に加えて、CSRF保護を使用している場合は、Webサービス要求に対してそれをオフにする必要があります。アプリケーションコントローラーの保護されたメソッドとして、以下を追加できます。
def protect_against_forgery?
unless request.format.xml? or request.format.json?
super
end
end
このように、HTMLリクエストは引き続きCSRFを使用します(またはそうではありません-環境内のconfig.action_controller.allow_forgery_protection = true/false
に依存します)。
私自身、セッションを宣言的にオフにできることを本当に逃しました(session :off
を使用)
...したがって、私はそれを「元に戻しました」-昔ながらのレール(<= 2.2)のように使用します:
もちろん、これには独自のDevise固有のハッキングが必要になる場合があります。これは、session_offによってコントローラーでsession == nil
が発生する可能性があるためです。また、2.3以降のほとんどのRails拡張機能は、怠惰なセッションを想定しているだけです。決してゼロになることはありません。
Imoの最善のアプローチは、Cookieセッションストアミドルウェアを削除することです。
これを行うには、これをapplication.rb(または必要に応じて特定の環境)に追加します。
# No session store
config.middleware.delete ActionDispatch::Session::CookieStore
代わりにこれを試してください
after_filter :skip_set_cookies_header
def skip_set_cookies_header
session.instance_variable_set('@loaded', false)
end
またはさらに良いことに、セッションデータが変更されていない場合は、常にSet-Cookieヘッダーを削除してください
before_filter :session_as_comparable_array # first before_filter
after_filter :skip_set_cookies_header # last after_filter
def session_as_comparable_array(obj = session)
@session_as_comparable_array = case obj
when Hash
obj.keys.sort_by(&:to_s).collect{ |k| [k, session_as_comparable_array(obj[k])] }
when Array
obj.sort_by(&:to_s).collect{ |k| session_as_comparable_array(k) }
else
obj
end
end
def skip_set_cookies_header
session.instance_variable_set('@loaded', false) if (@session_as_comparable_array == session_as_comparable_array)
end