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

Fil*_*ero 12 authentication api json ruby-on-rails devise

我正在我的应用程序上使用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
Run Code Online (Sandbox Code Playgroud)

application_controller.rb仍然有before_filter :authenticate_user!代码.

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

然后,遵循下面的Steve Jorgensen的解决方案,确保我的API模块继承ActionController::Base而不是ApplicationController绕过Devise的before_filter :authenticate_user!代码ApplicationController.

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

module Api
  module V1
    class RestaurantsController < ApplicationController
    ...
Run Code Online (Sandbox Code Playgroud)

module Api
  module V1
    #Replace 'ApplicationController' with 'ActionController::Base'
    class RestaurantsController < ActionController::Base
    ...
Run Code Online (Sandbox Code Playgroud)

Sea*_*ean 14

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

class Api::ApplicationController < ApplicationController

skip_before_filter :authenticate_user!
Run Code Online (Sandbox Code Playgroud)

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

  • `before_filter` 在 Rails 5.0 中已弃用,并在 Rails 5.1 中删除 https://github.com/rails/rails/blob/v5.0.0.beta2/actionpack/lib/abstract_controller/callbacks.rb#L190-L193。将“skip_before_filter”替换为“skip_before_action”,将“before_filter”替换为“before_action”,它们是等效的。 (3认同)

Gaz*_*ler 10

您可以before_filter在控制器中执行此操作.

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

class SomeController < ApplicationController
  before_filter :authenticate_user!
end
Run Code Online (Sandbox Code Playgroud)

您可以定义一个不同的方法(理想情况下在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
Run Code Online (Sandbox Code Playgroud)

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


Ste*_*sen 7

没有人提到的一个选项是为API提供一组完全独立的控制器,这些控制器不会从中继承ApplicationController.

我已经看到了API控制器存在于文件中的模式,例如,/app/controllers/api/v1/somethings.rb可通过以下路由访问/api/v1/somethings.每个特定的API控制器都继承自继承自的基本API控制器ActionController::Base,因此不包括在其上定义的任何过滤器ApplicationController.


nie*_*els 5

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
Run Code Online (Sandbox Code Playgroud)

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

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
Run Code Online (Sandbox Code Playgroud)