Rails 3 deshabilitar las cookies de sesión

Tengo una API RESTful escrita en RoR 3. Tengo que hacer que mi aplicación no envíe “encabezado Set-Cookie” (los clientes autorizan el uso del parámetro auth_token).

Intenté utilizar session :off y reset_session pero no tiene sentido. Estoy usando el devise como marco de autenticación.

Aquí está mi ApplicationController

 class ApplicationController  :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 

Como se menciona en un comentario sobre la respuesta de John, borrar la sesión no evitará que se envíe la cookie de sesión. Si desea eliminar por completo la cookie que se envía, debe utilizar el middleware 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 

Úselo creando un inicializador con el siguiente cuerpo:

 Rails.application.config.middleware.insert_before ::ActionDispatch::Cookies, ::CookieFilter 

Para evitar que el filtro de cookies termine en los rastros de la stack de la aplicación, lo que a veces puede ser confuso, es posible que desee silenciarlo en el backtrace (suponiendo que lo coloque en lib/cookie_filter.rb ):

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

Use la opción incorporada .

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

o el equivalente

 request.session_options[:skip] = true 

Puede encontrar la documentación aquí http://doc.rubyists.com/rack/Rack/Session/Abstract/ID.html

No estoy seguro de cuándo lo agregaron a Devise, pero parece que hay una configuración que le permitirá desactivar el envío de la cookie de sesión cuando use 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] 

Funciona bien El único problema que tuve fue que aún necesitaba poder hacer una solicitud inicial a token_controller para generar / recuperar el token. Es decir POST /api/v1/tokens.json , que desafortunadamente causaría que se devuelva una cookie de sesión para esa solicitud.

Así que terminé implementando el CookieFilter CookieFilter que Ryan Ahearn escribió anteriormente de todos modos.

Además, como mi aplicación tiene tanto una interfaz web como una api de JSON, solo quería filtrar las cookies para la API de JSON. Así que modifiqué la clase CookieFilter para verificar primero las solicitudes pertenecientes a la API:

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

No estoy seguro de si hay una mejor manera de hacerlo …

Otra solución: en el controlador que desea evitar las cookies, agregue esto:

 after_filter :skip_set_cookies_header def skip_set_cookies_header request.session_options = {} end 

Si tiene un conjunto de controladores api, configúrelo en una clase api_controller y deje que sus otros controladores hereden el api_controller.

Esto omite configurar el encabezado Set-Cookie porque la sesión está vacía.

El CookieSessionStore predeterminado no envía un encabezado “Set-Cookie” a menos que se agregue algo a la sesión. ¿Hay algo en tu stack escribiendo en la sesión? (Probablemente es Devise)

session :off ha sido desaprobada:

 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 

Si algo en tu stack está configurando la información de la sesión, puedes session.clear usando session.clear como sigue:

 after_filter :clear_session def clear_session session.clear end 

Lo cual evitará que se envíe el encabezado Set-Cookie

Además de la respuesta de John, si usa la protección CSRF, deberá desactivarla para las solicitudes de servicio web. Puede agregar lo siguiente como un método protegido en su controlador de aplicación:

  def protect_against_forgery? unless request.format.xml? or request.format.json? super end end 

De esta forma, las solicitudes HTML aún usan CSRF (o no, depende de config.action_controller.allow_forgery_protection = true/false en el entorno).

Yo realmente extrañé poder desactivar declarativamente sesiones (usando session :off )

… así que lo trajé “de vuelta” – úselo como en los viejos Rails (< = 2.2):

que por supuesto esto podría requerir un hackeo adicional específico de tu dispositivo, ya que session_off podría causar session == nil en un controlador, y la mayoría de las extensiones de Rails desde 2.3 simplemente asumen una sesión perezosa que no será nula.

https://github.com/kares/session_off

Imo, el mejor enfoque es simplemente eliminar el middleware de la tienda de sesiones de cookies.

Para hacerlo, agregue esto a su application.rb (o a un entorno específico si es necesario):

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

Prueba esto en cambio

 after_filter :skip_set_cookies_header def skip_set_cookies_header session.instance_variable_set('@loaded', false) end 

O incluso mejor, siempre quite el encabezado Set-Cookie cuando los datos de la sesión no cambien

 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