ruby on rails - scotch - Extender Devise SessionsController para autenticarse con JSON
scotch rails api only (7)
Estoy tratando de construir una API de rieles para una aplicación de iPhone. Devise funciona bien para los inicios de sesión a través de la interfaz web, pero necesito poder crear y destruir sesiones usando REST API y quiero usar JSON en lugar de tener que hacer un POST en el controlador de sesiones y tener que analizar el HTML y manejar un redirigir
Pensé que podría hacer algo como esto:
class Api::V1::SessionsController < Devise::SessionsController
def create
super
end
def destroy
super
end
end
y en config / routes.rb agregué:
namespace :api do
namespace :v1 do
resources :sessions, :only => [:create, :destroy]
end
end
las rutas de rake muestran que las rutas están configuradas correctamente:
api_v1_sessions POST /api/v1/sessions(.:format) {:action=>"create", :controller=>"api/v1/sessions"}
api_v1_session DELETE /api/v1/sessions/:id(.:format) {:action=>"destroy", :controller=>"api/v1/sessions"}
Cuando PUBLICO a / usuario / sesiones todo funciona bien. Obtengo algo de HTML y un 302.
Ahora si PUBLICO a / api / v1 / sessions, obtengo:
Acción desconocida AbstractController :: ActionNotFound
curl -v -H ''Content-Type: application/json'' -H ''Accept: application/json'' -X POST http://localhost:3000/api/v1/sessions -d "{''user'' : { ''login'' : ''test'', ''password'' : ''foobar''}}"
Del rdoc para el #devise_scope del dispositivo:
Establece el alcance del dispositivo que se utilizará en el controlador. Si tiene rutas personalizadas, debe llamar a este método (también con alias como: as) para especificar a qué controlador está dirigido.
as :user do
get "sign_in", :to => "devise/sessions#new"
end
Tenga en cuenta que no puede tener dos ámbitos asignados a la misma URL. Y recuerde, si intenta acceder a un controlador de diseño sin especificar un alcance, se generará un error de ActionNotFound.
Parece que debes envolverlo en un bloque #as:
as :user do
namespace :api do
namespace :v1 do
resources :sessions, :only => [:create, :destroy]
end
end
end
Esto es lo que finalmente funcionó.
class Api::V1::SessionsController < Devise::SessionsController
def create
respond_to do |format|
format.html { super }
format.json {
warden.authenticate!(:scope => resource_name, :recall => "#{controller_path}#new")
render :status => 200, :json => { :error => "Success" }
}
end
end
def destroy
super
end
end
También cambie routes.rb, recuerde que el orden es importante.
devise_for :users, :controllers => { :sessions => "api/v1/sessions" }
devise_scope :user do
namespace :api do
namespace :v1 do
resources :sessions, :only => [:create, :destroy]
end
end
end
resources :users
No estoy seguro de que se utilicen formatos de navegación, una API no es realmente eso ...
Por esta publicación de blog simplemente agrega
respond_to :html, :json
a tus controladores.
Resolví el problema creando un pequeño servicio que dispensa tokens de autenticación. Escribí una publicación en el blog sobre esto: http://matteomelani.wordpress.com/2011/10/17/authentication-for-mobile-devices/ . También puede obtener el código aquí: https://github.com/matteomelani/Auth-Token-Service-Prototype .
Terminé usando una combinación de la respuesta de @ akshay y la respuesta de @mm2001.
class Api::SessionsController < Devise::SessionsController
def create
warden.authenticate!(:scope => resource_name, :recall => "#{controller_path}#failure")
render :json => {:success => true}
end
def destroy
Devise.sign_out_all_scopes ? sign_out : sign_out(resource_name)
render :json => {}
end
def failure
render :json => {:success => false, :errors => ["Login Failed"]}
end
end
... y en el inicializador del dispositivo, tuve que hacer esto para obtener el método #create para usar mi controlador :recall
# config/initializers/devise.rb
config.navigational_formats = [:"*/*", "*/*", :html, :json]
Esto es con el Devise 1.5.1 y Rails 3.1.
Una respuesta reciente aquí: http://jessehowarth.com/devise tiene más detalles (por Uso de Devise 1.3 para autenticar las solicitudes de inicio de sesión de JSON )
Una solución alternativa para crear / destruir sesiones es usar el módulo token_authenticatable
de Devise, y luego actualizar las otras funciones en su API para que tomen el token como un parámetro obligatorio. Este es posiblemente un diseño más ReSTful, ya que conserva la apatridia (es decir, no hay ningún estado de sesión en ninguna parte). Por supuesto, este consejo es válido para su API JSON, pero no recomendaría lo mismo para su interfaz de usuario HTML (las cadenas de token largas en la barra de URL de su navegador no son una buena idea).
Vea here para un ejemplo.