Ruby-on-rails 扩展设计 SessionsController 以使用 JSON 进行身份验证

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/4857855/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-03 00:15:42  来源:igfitidea点击:

Extending Devise SessionsController to authenticate using JSON

ruby-on-railsrubyauthenticationdevise

提问by Akshay Kumar

I am trying to build a rails API for an iphone app. Devise works fine for logins through the web interface but I need to be able to create and destroy sessions using REST API and I want to use JSON instead of having to do a POST on the sessions controller and having to parse the HTML and deal with a redirect.

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

I thought I could do something like this:

我以为我可以做这样的事情:

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

and in config/routes.rb I added:

在 config/routes.rb 中我添加了:

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

rake routes shows the routes are setup properly:

rake routes 显示路由设置正确:

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

When I POST to /user/sessions everything works fine. I get some HTML and a 302.

当我 POST 到 /user/sessions 时一切正常。我得到一些 HTML 和一个 302。

Now if I POST to /api/v1/sessions I get:

现在,如果我 POST 到 /api/v1/sessions 我得到:

Unknown action AbstractController::ActionNotFound

未知动作 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'}}"

采纳答案by Akshay Kumar

This is what finally worked.

这就是最终奏效的方法。

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  

Also change routes.rb, remember the order is important.

还要更改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

回答by declan

I ended up using a combination of @akshay's answer and @mm2001's answer.

我最终使用了@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

... and in the devise initializer, I had to do this to get the #create method to use my :recallhandler

...在设计初始值设定项中,我必须这样做才能让 #create 方法使用我的:recall处理程序

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

This is with Devise 1.5.1 and Rails 3.1.

这是与设计 1.5.1 和 Rails 3.1。

回答by mm2001

回答by Matteo Melani

I solved the problem by creating a small service that dispenses authentication tokens. I wrote a blog post about it: http://matteomelani.wordpress.com/2011/10/17/authentication-for-mobile-devices/. You can also get the code here: https://github.com/matteomelani/Auth-Token-Service-Prototype.

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

回答by Ricky Robinson

An alternative solution to creating/destroying sessions is to use Devise's token_authenticatablemodule, and then update the other functions in your API so that they take the token as a mandatory parameter. This is arguably a more ReSTful design, since it retains statelessness (i.e., there's no session state anywhere). Of course, this advice holds for your JSON API, but I wouldn't recommend the same for your HTML UI (long token strings in your browser's URL bar are not a pretty sight).

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

See herefor an example.

有关示例,请参见此处

回答by Michael Nutt

From the rdoc for devise's #devise_scope:

来自设计的#devise_scope 的 rdoc:

Sets the devise scope to be used in the controller. If you have custom routes, you are required to call this method (also aliased as :as) in order to specify to which controller it is targetted.

设置要在控制器中使用的设计范围。如果您有自定义路由,则需要调用此方法(也称为 :as)以指定它的目标控制器。

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

Notice you cannot have two scopes mapping to the same URL. And remember, if you try to access a devise controller without specifying a scope, it will raise ActionNotFound error.

请注意,您不能将两个范围映射到同一个 URL。请记住,如果您尝试在不指定范围的情况下访问设计控制器,则会引发 ActionNotFound 错误。

It looks like you need to wrap it in a #as block:

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

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

回答by aceofspades

Not sure navigation-formats should be used, an API isn't really that...

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

Per this blog postjust add

根据这篇博文,只需添加

respond_to :html, :json

to your controllers.

到您的控制器。