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。为通过网络登录界面设计没问题但是我需要能够使用REST API创建和销毁会话,我想使用JSON而不是会话控制器和上一篇文章需要解析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 /路线。rb我补充说:
namespace :api do
namespace :v1 do
resources :sessions, :only => [:create, :destroy]
end
end
rake routes shows the routes are setup properly:
耙路显示路线设置正确:
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.
当我发布到/用户/会话时,一切正常。我得到一些HTML和302。
Now if I POST to /api/v1/sessions I get:
现在如果我发布到/api/v1/session,我得到:
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'}}"
7 个解决方案
#1
39
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.
同时改变路线。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
#2
10
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 :recall
handler
…在设计初始化器中,我必须这样做才能获得#create方法来使用my:recall handler
# 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。
#3
8
A recent answer here: http://jessehowarth.com/devise has some more detail (per Using Devise 1.3 to authenticate JSON login requests)
这里有一个最近的答案:http://jessehowarth.com/智囊团有一些更详细的信息(每个人都使用design1.3来验证JSON登录请求)
#4
5
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/authentic-for mobile-devices/。您还可以在这里获得代码:https://github.com/matteomelani/auth-token-service prototype。
#5
1
From the rdoc for devise's #devise_scope:
从rdoc设计的#devise_scope:
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 block:
as :user do
namespace :api do
namespace :v1 do
resources :sessions, :only => [:create, :destroy]
end
end
end
#6
1
An alternative solution to creating/destroying sessions is to use Devise's token_authenticatable
module, 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).
创建/销毁会话的另一种解决方案是使用设计的token_authenticatable模块,然后更新您的API中的其他函数,以便它们将令牌作为一个强制参数。这可以说是一个更加ReSTful的设计,因为它保留了无状态性。,在任何地方都没有会话状态。当然,这个建议适用于JSON API,但我不建议您的HTML UI也采用这种方法(浏览器URL栏中的长令牌字符串不是很理想)。
See here for an example.
请看这里的一个例子。
#7
0
Not sure navigation-formats should be used, an API isn't really that...
不确定是否应该使用导航格式,API并不是。
Per this blog post just add
根据这篇博文,只需添加
respond_to :html, :json
to your controllers.
你的控制器。
#1
39
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.
同时改变路线。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
#2
10
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 :recall
handler
…在设计初始化器中,我必须这样做才能获得#create方法来使用my:recall handler
# 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。
#3
8
A recent answer here: http://jessehowarth.com/devise has some more detail (per Using Devise 1.3 to authenticate JSON login requests)
这里有一个最近的答案:http://jessehowarth.com/智囊团有一些更详细的信息(每个人都使用design1.3来验证JSON登录请求)
#4
5
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/authentic-for mobile-devices/。您还可以在这里获得代码:https://github.com/matteomelani/auth-token-service prototype。
#5
1
From the rdoc for devise's #devise_scope:
从rdoc设计的#devise_scope:
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 block:
as :user do
namespace :api do
namespace :v1 do
resources :sessions, :only => [:create, :destroy]
end
end
end
#6
1
An alternative solution to creating/destroying sessions is to use Devise's token_authenticatable
module, 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).
创建/销毁会话的另一种解决方案是使用设计的token_authenticatable模块,然后更新您的API中的其他函数,以便它们将令牌作为一个强制参数。这可以说是一个更加ReSTful的设计,因为它保留了无状态性。,在任何地方都没有会话状态。当然,这个建议适用于JSON API,但我不建议您的HTML UI也采用这种方法(浏览器URL栏中的长令牌字符串不是很理想)。
See here for an example.
请看这里的一个例子。
#7
0
Not sure navigation-formats should be used, an API isn't really that...
不确定是否应该使用导航格式,API并不是。
Per this blog post just add
根据这篇博文,只需添加
respond_to :html, :json
to your controllers.
你的控制器。