web-dev-qa-db-fra.com

Extension de Devise SessionsController pour s'authentifier à l'aide de JSON

J'essaie de créer une Rails API pour une application iphone. Devise fonctionne très bien pour les connexions via l'interface Web, mais je dois pouvoir créer et détruire des sessions en utilisant REST API et je veux utiliser JSON au lieu d'avoir à faire un POST sur le contrôleur de sessions et avoir à analyser le HTML et gérer une redirection.

Je pensais pouvoir 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 indique que les itinéraires sont correctement configurés:

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

Quand je POST to/user/sessions tout fonctionne bien. J'obtiens du HTML et un 302.

Maintenant, si je POST to/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'}}"
47
Akshay Kumar

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  

Modifiez également routes.rb, n'oubliez pas que la commande est 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
41
Akshay Kumar

J'ai fini par utiliser une combinaison de la réponse de @ akshay et de la réponse 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'initialiseur de devise, je devais le faire pour obtenir la méthode #create pour utiliser mon :recall gestionnaire

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

C'est avec Devise 1.5.1 et Rails 3.1.

10
declan
8
mm2001

J'ai résolu le problème en créant un petit service qui distribue des jetons d'authentification. J'ai écrit un 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 .

5
Matteo Melani

Une solution alternative à la création/destruction de sessions consiste à utiliser token_authenticatable module, puis mettez à jour les autres fonctions de votre API afin qu'elles prennent le jeton comme paramètre obligatoire. Il s'agit sans doute d'une conception plus ReSTful, car elle conserve l'apatridie (c'est-à-dire qu'il n'y a aucun état de session nulle part). Bien sûr, ce conseil vaut pour votre API JSON, mais je ne recommanderais pas la même chose pour votre interface HTML (les longues chaînes de jetons dans la barre d'URL de votre navigateur ne sont pas une jolie vue).

Voir ici pour un exemple.

1
Ricky Robinson

Du rdoc pour #devise_scope de devise:

Définit la portée de l'appareil à utiliser dans le contrôleur. Si vous avez des itinéraires personnalisés, vous devez appeler cette méthode (également alias: as) afin de spécifier à quel contrôleur elle est ciblée.

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

Notez que vous ne pouvez pas avoir deux étendues mappées sur la même URL. Et n'oubliez pas que si vous essayez d'accéder à un contrôleur de devise sans spécifier de portée, cela générera une erreur ActionNotFound.

Il semble que vous ayez besoin de l'envelopper dans un bloc #as:

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

Pas sûr que les formats de navigation doivent être utilisés, une API n'est pas vraiment ça ...

Par ceci article de blog il suffit d'ajouter

respond_to :html, :json

à vos contrôleurs.

0
aceofspades