Rails 3 отключает сеансовые куки - PullRequest
26 голосов
/ 25 марта 2011

У меня RESTful API, написанный на RoR 3. Я должен заставить свое приложение не отправлять «заголовок 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

Ответы [ 9 ]

39 голосов
/ 31 августа 2012

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

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

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

request.session_options[:skip] = true

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

34 голосов
/ 10 ноября 2011

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

Rails.backtrace_cleaner.add_silencer { |line| line.start_with? "lib/cookie_filter.rb" }
8 голосов
/ 11 января 2013

Я не уверен, когда они добавили его в 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'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 сеанса для этого запроса.

Так что я в итоге реализовал CookieFilter инициализатор, который Райан Ахерн написал выше в любом случае.Поскольку мое приложение имеет как веб-интерфейс, так и API-интерфейс JSON, я только хотел отфильтровать файлы cookie для API-интерфейса JSON.Поэтому я изменил класс CookieFilter, чтобы сначала проверить, принадлежат ли запросы к API:

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

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

5 голосов
/ 07 декабря 2012

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

after_filter :skip_set_cookies_header

def skip_set_cookies_header
  request.session_options = {}
end

Если у вас есть набор контроллеров api, задайте его в классе api_controller и позвольте другим контроллерам наследовать api_controller.

При этом пропускается настройка заголовка Set-Cookie, поскольку параметры сеанса пусты.

4 голосов
/ 25 марта 2011

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

3 голосов
/ 29 июля 2011

В дополнение к ответу Джона, если вы используете защиту 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 в среде).

2 голосов
/ 12 января 2012

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

... таким образом, я вернул его "назад" - используйте его так же, как в plain-old-rails (<=2.2): </p>

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

https://github.com/kares/session_off

1 голос
/ 06 сентября 2012

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

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

# No session store
config.middleware.delete ActionDispatch::Session::CookieStore
0 голосов
/ 17 ноября 2011

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

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
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...