我在我的应用程序中使用Devise,并希望创建一个全局API密钥,可以访问任何人账户的JSON数据而无需登录。
例如,假设我的API密钥是1234
,并且有两个用户分别创建了两个不同的餐厅。
- 用户1 - 餐厅1(/restaurants/1)
- 用户2 - 餐厅2(/restaurants/2)
如果我打开一个全新的浏览器并且没有登录,通过我的URL传入.../restaurants/2.json?api_key=1234
,我应该能够访问该餐厅的JSON数据,而无需像用户2一样登录。
最佳方法是什么?
我已经按照Railscast#352 Securing an 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!
的代码。
解决方案
我首先按照 Railscast #350 REST API版本控制 的方法,将所有JSON API调用移至/apps/api/v1/...
接着,遵循Steve Jorgensen在下方的解决方案,确保我的API模块从ActionController::Base
继承,而不是从ApplicationController
,这样它就可以绕过ApplicationController
中Devise的before_filter :authenticate_user!
代码。
所以,我的Edit 2的代码变成了这样:
module Api
module V1
class RestaurantsController < ApplicationController
...
module Api
module V1
#Replace 'ApplicationController' with 'ActionController::Base'
class RestaurantsController < ActionController::Base
...
before_filter
在Rails 5.0中已被弃用,并在Rails 5.1中删除。请使用等效的skip_before_action
和before_action
替换skip_before_filter
和before_filter
。具体信息请参见https://github.com/rails/rails/blob/v5.0.0.beta2/actionpack/lib/abstract_controller/callbacks.rb#L190-L193。 - stwr667