如何在使用API​​密钥时跳过Devise身份validation?

我正在我的应用程序上使用Devise,并希望创建一个全局API密钥,可以访问任何人的帐户的JSON数据,而无需登录。

例如,假设我的API密钥是1234 ,我有两个用户创建了两个不同的餐厅。

  • 用户1 – 餐厅1(/餐厅/ 1)
  • 用户2 – 餐厅2(/餐厅/ 2)

我打开一个全新的浏览器,没有登录任何东西,我传入我的URL .../restaurants/2.json?api_key=1234 ,我应该能够访问该餐厅的JSON数据,而无需登录- 作为用户2

什么是最好的方法呢?

我已经按照Railscast#352保护API,所以我可以通过传入API密钥来访问JSON的东西,但我必须登录才能看到任何内容。

编辑1:使用CanCan

我应该提一下,我也在使用CanCan作为角色,但不确定在这种情况下是否会扮演任何角色(双关语)。

编辑2:使用API​​版本控制

我按照Railscast#350和#352教你如何创建REST API版本以及如何使用API​​密钥保护它。

这是我的controllers / api / v1 / restaurants / restaurants_controller.rb的样子:

 module Api module V1 class RestaurantsController < ApplicationController before_filter :restrict_access respond_to :json def index respond_with Restaurant.all end def show respond_with Restaurant.find(params[:id]) end private def restrict_access api_key = ApiKey.find_by_access_token(params[:api_key]) head :unauthorized unless api_key end end end end 

而我的application_controller.rb仍然有before_filter :authenticate_user! 代码在里面。

我首先在REST API版本控制上关注Railscast#350 ,并将所有JSON API调用移到/apps/api/v1/...

然后,遵循下面的Steve Jorgensen的解决方案,确保我的API模块inheritance自ActionController::Base而不是ApplicationController以便它绕过Devise的before_filter :authenticate_user! ApplicationController代码。

所以,我的Edit 2代码看起来像这样:

 module Api module V1 class RestaurantsController < ApplicationController ... 

 module Api module V1 #Replace 'ApplicationController' with 'ActionController::Base' class RestaurantsController < ActionController::Base ... 

没有人提到的一个选项是为API提供一组完全独立的控制器,它不从ApplicationControllerinheritance。

我已经看到了API控制器所使用的模式,例如/app/controllers/api/v1/somethings.rb等文件,可以通过/api/v1/somethings等路由访问。 每个特定的API控制器都inheritance自从ActionController::Baseinheritance的基本API控制器,因此不包括ApplicationController定义的任何filter。

我知道它被问到这已经有一段时间了,但我想我会再投入一个我过去使用过的选项

 class Api::ApplicationController < ApplicationController skip_before_filter :authenticate_user! 

这假设您的API目录中有一个应用程序控制器,您的所有api控制器都inheritance自该控制器。 如果没有,您可以将跳过放在每个控制器中。

您可以使用Controller中的before_filter执行此操作。

目前,你可能有类似的东西:

 class SomeController < ApplicationController before_filter :authenticate_user! end 

您可以定义一个不同的方法(理想情况下在ApplicationController中),而不是调用它

 class ApplicationController < ActionController::Base before_filter :authenticate_or_token private def authenticate_or_token if params[:api_key] == 1234 @current_user = User.new(:admin => true, :any => "other", :required => "fields") return current_user end authenticate_user! end 

我建议使用更强大的身份validation方法,如OAuth,但这应该适用于简单的基于1键的身份validation。

Gazler的另一种选择是使用以下:

 class ApplicationController < ActionController::Base before_filter :authenticate_user!, except: :some_json_method def some_json_method render :nothing unless params[:api_key] == '1234' render :json end end 

这样您就不会将整个应用程序打开给密钥持有者(根据您的需要,您是否需要)。 如果您需要多个方法打开键,您可能还可以使用以下内容:

 class ApplicationController < ActionController::Base JSON_METHODS = [method_1, method2] before_filter :authenticate_user!, except: JSON_METHODS before_filter :authenticate_token, only: JSON_METHODS private def authenticate_token params[:api_key] == '1234' end end