扩展Devise SessionsController以使用JSON进行身份验证

时间:2011-02-01 00:59:39

标签: ruby-on-rails ruby authentication devise

我正在尝试为iPhone应用程序构建rails API。 Devise适用于通过Web界面登录,但我需要能够使用REST API创建和销毁会话,我想使用JSON而不必在会话控制器上执行POST并且必须解析HTML并处理重定向。

我以为我可以这样做:

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

并在config / routes.rb中添加:

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

rake路线显示路线设置正确:

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

当我发布到/ user / sessions时,一切正常。我得到了一些HTML和302。

现在,如果我发布到/ api / v1 / sessions,我会得到:

  

未知行动   一个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'}}"

7 个答案:

答案 0 :(得分:40)

这是最终奏效的。

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  

同时更改routes.rb,记住顺序很重要。

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

答案 1 :(得分:10)

我最终结合了@ akshay的回答和@ 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

...在设计初始化程序中,我必须这样做以使#create方法使用我的:recall处理程序

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

这是Devise 1.5.1和Rails 3.1。

答案 2 :(得分:8)

答案 3 :(得分:5)

我通过创建一个分配身份验证令牌的小服务解决了这个问题。我写了一篇关于它的博客文章:http://matteomelani.wordpress.com/2011/10/17/authentication-for-mobile-devices/。 您也可以在此处获取代码:https://github.com/matteomelani/Auth-Token-Service-Prototype

答案 4 :(得分:1)

来自devise的#devise_scope的rdoc:

设置要在控制器中使用的设备范围。如果您有自定义路线, 您需要调用此方法(也别名为:as)才能指定 它被定位到哪个控制器。

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

请注意,您不能将两个范围映射到同一个URL。请记住,如果 你尝试访问设备控制器而不指定范围,它会 提出ActionNotFound错误。

看起来您需要将其包装在#as块中:

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

答案 5 :(得分:1)

创建/销毁会话的另一种解决方案是使用Devise的token_authenticatable模块,然后更新API中的其他功能,以便将令牌作为必需参数。这可以说是一个更具ReSTful的设计,因为它保留了无状态(即,任何地方都没有会话状态)。当然,这个建议适用于您的JSON API,但我不建议您的HTML UI使用相同的内容(浏览器的URL栏中的长令牌字符串不是很明显)。

有关示例,请参阅here

答案 6 :(得分:0)

不确定应该使用导航格式,API不是真的......

按此blog post添加

respond_to :html, :json

到您的控制器。