47 votes

Extension de Devise SessionsController pour s'authentifier en utilisant JSON

J'essaie de construire une API pour rails pour une application iphone. Devise fonctionne bien pour les connexions via l'interface web mais j'ai besoin de pouvoir créer et détruire des sessions en utilisant l'API REST et je veux utiliser JSON au lieu de devoir faire un POST sur le contrôleur de sessions et de devoir analyser le HTML et gérer une redirection.

Je pensais que je pourrais faire quelque chose comme ça :

class Api::V1::SessionsController < Devise::SessionsController  
  def create
    super
  end  
  def destroy
    super
  end  
end

et dans config/routes.rb j'ai ajouté :

namespace :api do
  namespace :v1 do
    resources :sessions, :only => [:create, :destroy]
  end
end

rake routes montre que les routes sont correctement configurées :

   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"}

Lorsque je POSTE dans /user/sessions, tout fonctionne bien. Je reçois du HTML et un 302.

Maintenant si je POST à /api/v1/sessions j'obtiens :

Action inconnue 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'}}"

41voto

Akshay Kumar Points 739

C'est ce qui a finalement fonctionné.

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  

Changez aussi routes.rb, rappelez-vous que l'ordre est important.

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

10voto

declan Points 2709

J'ai fini par utiliser une combinaison de la réponse de @akshay et de celle 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

... et dans l'initialisateur de la devise, j'ai dû faire ceci pour que la méthode #create utilise mon :recall manipulateur

# config/initializers/devise.rb
config.navigational_formats = [:"*/*", "*/*", :html, :json]

Ceci avec Devise 1.5.1 et Rails 3.1.

8voto

mm2001 Points 1193

5voto

Matteo Melani Points 1281

J'ai résolu le problème en créant un petit service qui distribue des jetons d'authentification. J'ai écrit un billet de blog à ce sujet : http://matteomelani.wordpress.com/2011/10/17/authentication-for-mobile-devices/ . Vous pouvez également obtenir le code ici : https://github.com/matteomelani/Auth-Token-Service-Prototype .

1voto

Michael Nutt Points 68

Extrait du rdoc pour le #devise_scope de devise :

Définit la portée de la devise à utiliser dans le contrôleur. Si vous avez des routes personnalisées, vous devez appeler cette méthode (également alias :as) afin de spécifier à quel contrôleur à quel contrôleur il est destiné.

as :user do
  get "sign_in", :to => "devise/sessions#new"
end

Notez que vous ne pouvez pas avoir deux scopes mappant à la même URL. Et n'oubliez pas que si vous essayez d'accéder à un contrôleur de devise sans spécifier une portée, il va l'erreur ActionNotFound.

On dirait que vous devez l'envelopper dans un bloc #as :

as :user do
  namespace :api do
    namespace :v1 do
      resources :sessions, :only => [:create, :destroy]
    end
  end
end

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X