Подтвердить что ты не робот

Rails 3 отключает файлы cookie сеанса

У меня есть RESTful API, написанный на RoR 3. Я должен заставить мое приложение не отправлять "Set-Cookie header" (клиенты авторизуются с использованием параметра 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
4b9b3361

Ответ 1

Как упоминается в комментарии к ответу Джона, очистка сеанса не будет препятствовать отправке 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 не попадал в трассировки стека приложений, что может иногда быть непонятным, вы можете отключить его в backtrace (предположив, что вы положили его в lib/cookie_filter.rb):

Rails.backtrace_cleaner.add_silencer { |line| line.start_with? "lib/cookie_filter.rb" }

Ответ 2

Используйте встроенную опцию.

env['rack.session.options'][:skip] = true

или эквивалентный

request.session_options[:skip] = true

Здесь вы можете найти документацию http://doc.rubyists.com/rack/Rack/Session/Abstract/ID.html

Ответ 3

Я не уверен, когда они добавили его в Devise, но, похоже, есть конфигурация, которая позволит вам отключить отправку файла cookie сеанса при использовании auth_token:

# 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 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, что, к сожалению, приведет к возврату куки файла сеанса для этого запроса.

Итак, я закончил реализацию intializer CookieFilter, который Райан Ahearn написал выше в любом случае.

Кроме того, поскольку мое приложение имеет как веб-интерфейс, так и JSON api, я только хотел отфильтровать файлы cookie для JSON api. Поэтому я изменил класс CookieFilter, чтобы сначала проверить запросы, принадлежащие api:

if env['PATH_INFO'].match(/^\/api/)
  Rack::Utils.delete_cookie_header!(headers, '_myapp_session')
end

Не уверен, есть ли лучший способ сделать это...

Ответ 4

Другое решение: В контроллере вы хотите избежать куки файлов, добавьте это:

after_filter :skip_set_cookies_header

def skip_set_cookies_header
  request.session_options = {}
end

Если у вас есть набор контроллеров api, установите это в классе api_controller и пусть ваши другие контроллеры наследуют api_controller.

Это пропускает значение Set-Cookie, поскольку выбор сеанса пуст.

Ответ 5

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

Ответ 6

В ответ на ответ Джона, если вы используете CSRF-защиту, вам нужно будет отключить это для запросов веб-сервисов. Вы можете добавить следующее в качестве защищенного метода в контроллер приложения:

  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 в среде).

Ответ 7

Я сам действительно пропустил возможность декларативно отключить сеансы (используя session :off)

... таким образом, я вернул его "назад" - используйте его точно так же, как в простых старых рельсах (< = 2,2):

чем, конечно, это может потребовать некоторого дополнительного специального взлома Devise, поскольку session_off может вызвать session == nil в контроллере, а большинство расширений rails с 2.3 просто предполагают ленивый сеанс, который никогда не будет ничем.

https://github.com/kares/session_off

Ответ 8

Ими лучшим подходом является простое удаление промежуточного программного обеспечения хранилища файлов cookie.

Для этого добавьте это в свой application.rb(или в конкретную среду, если необходимо):

# No session store
config.middleware.delete ActionDispatch::Session::CookieStore

Ответ 9

Попробуйте это вместо

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