ruby-on-rails - rails : Authenticate before routing

标签 ruby-on-rails ruby-on-rails-4

什么。

我正在尝试在我的 Rails API 上实现基于 token 的基本身份验证。它适用于现有路线,但有一个问题:

当未经身份验证的用户访问不存在的路由时,它会显示 404 - Not found页面,而不是 401 - Unauthorized .如何让 Rails 检查身份验证 之前 验证路线?

这是我的application_controller.rb :

class Api::V1::ApiController < ApplicationController
  # Main controller inherited by all API controllers

  # For APIs, you may want to use :null_session instead.
  protect_from_forgery with: :null_session

  # Enforce site-wide authentication
  before_action :authenticate

  def authenticate
    authenticate_token || render_unauthorized
  end

  def authenticate_token
    # Can we find a user with the authentication token used?
    authenticate_with_http_basic do |u, p|
      # Only search active, private keys
      @api_key = ApiKey.active.find_by(api_key: u, is_secret: true)
      @user = @api_key.user if @api_key

      return @api_key
    end
  end

  def render_unauthorized
    # Displays the Unauthorized message
    render json: JSON.pretty_generate({ 
      error: { 
        type: "unauthorized",
        message: "This page cannot be accessed without a valid API key."
        } 
      }), status: 401
  end
end

为什么

可以这样想:有人在办公室拦住你问路。你是先让他们出示一些身份证,还是只是给他们指路?

如果它是一个公职,我只是给他们指路..但如果我们在中央情报局受限制的特殊项目部门,我不在乎你要去哪里(即使你告诉我你也是如此)正在寻找 Office 404,我知道它不存在):我想先查看一些 ID。

编辑:使用基本身份验证

我最初提到了基于 token 的身份验证,但它实际上是基本身份验证(使用“用户名”=“ token ”)。

最佳答案

由于@rich-peck 解释的原因,使用内置的rails 身份验证无法实现您想要的。 Rails 首先评估您的路线,然后将请求传递给 Controller ​​。

你有两个选择。首先,完全按照 Stripe 的人正在做的事情做。将身份验证委托(delegate)给应用服务器前面的 Web 服务器(在他们的情况下为 nginx)。

$ curl -I https://api.stripe.com/this/route/doesnt/exist
HTTP/1.1 401 Unauthorized
Server: nginx
Date: Fri, 08 Aug 2014 21:21:49 GMT
Content-Type: application/json;charset=utf-8
Www-Authenticate: Basic realm="Stripe"
Cache-Control: no-cache, no-store
Stripe-Version: 2014-08-04
Strict-Transport-Security: max-age=31556926; includeSubDomains

或者,如果您想/需要将其保留在 ruby​​-land 中,您可以使用机架中间件,该中间件将在 rails 加载您的路线之前进行身份验证。你可以试试https://github.com/iain/rack-token_auth
$ bin/rake middleware
...snip a bunch of middleware...
use Rack::TokenAuth
run Dummy::App::Application.routes

更新:使用 HTTP 基本身份验证

在这种情况下,您根本不需要其他库,因为 rack 通过 Rack::Auth::Basic 内置了对 http 基本身份验证的支持。中间件,例如
config.middleware.use Rack::Auth::Basic do |username, password|
  username == "bob" && password == "secret"
end

更新:我可以对 API 应用身份验证吗?命名空间?

这取决于。因为 rack 中间件在 rails 加载你的路由、 Controller 等之前运行,所以它不知道你的命名空间。尽管如此,如果您的命名空间 Controller 也在 URL 级别命名空间,例如全部在/api ,您可以查看request.path是否应用认证。

您可以创建一个新的机架中间件来装饰Rack::Auth::Basic这种行为,例如
class MyAPIAuth < Rack::Auth::Basic
  def call(env)
    request = Rack::Request.new(env)

    if request.path =~ /\A\/api\/?/
      super
    else
      @app.call(env)
    end
  end
end

# change your configuration to use your middleware
config.middleware.use MyAPIAuth do |username, password|
  username == "bob" && password == "secret"
end

关于ruby-on-rails - rails : Authenticate before routing,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24706854/

相关文章:

ruby-on-rails-4 - 如何在 rails activeadmin 上更改 css?

ruby-on-rails - 如何使用 RubyMine 进行远程调试?

html - 使用 Bootstrap 和 Rails 让 HTML <body> 填充整个垂直空间?

ruby-on-rails - 投票应该是 RoR 应用程序中自己的模型吗?

ruby-on-rails - 我如何将 rspec 与已清理的 YAML 固定装置一起使用?

ruby-on-rails - Rails 中一列字段的多个值

ruby-on-rails - 如何对计算出的值排序?

ruby-on-rails - 更改要加载的 spree 应用程序布局文件

ruby-on-rails - 在 Multi-Tenancy 应用程序上为租户自定义 CSS 的最佳方法?

ruby-on-rails - rails 4 : around_action with parameter