如何处理 Grape API 和 token_and_options 中的身份验证令牌字符串?

How to handle authentication token string in Grape API and token_and_options?

我正在使用 Ember front-end 和 Grape API 并验证一个页面,我有类似的东西:

  def current_user
    return nil if headers['Authorization'].nil?

    @current_user ||= User.find_by_authentication_token(
      headers['Authorization']
    )
  end

目前我正在使用 ember-simple-auth 发送类似于 header:

的内容
Token token="n2Rs5tokenLH", email="my@email.com"

查看葡萄记录器:

  User Load (38.1ms)  SELECT  "users".* FROM "users"  WHERE "users"."authentication_token" = 'Token token="n2Rs5tokenLH", email="my@email.com"' LIMIT 1

现在rails我通常使用authenticate_or_request_with_http_token来处理这个问题。而且我不想使用 gsub 或正则表达式之类的东西手动处理这个问题。在 Grape 中处理这个问题的最佳方法是什么?

请注意,Grape API 安装在 rails 项目和 app/api/backend/v1/default.rb 内:

module Backend
  module V1
    module Defaults
      extend ActiveSupport::Concern

      included do
        version 'v1', using: :path
        format :json
        prefix :api

        rescue_from :all do |e|
          Backend::Base.logger.error e
        end

        helpers do
          def current_user
            return nil if headers['Authorization'].nil?

            @current_user ||= User.find_by_authentication_token(
              headers['Authorization']
            )
          end

          def authenticate!
            error!('401 Unauthorized', 401) unless current_user
          end
        end
      end
    end
  end
end

编辑:

我刚刚发现我可以使用 ActionController::HttpAuthentication::Token.token_and_options 来完成这项工作,但是我不确定我应该如何将其包含在 Grape 项目中。

应用程序的结构如下所示:

⇒  tree app/api
app/api
└── backend
    ├── base.rb
    └── v1
        ├── defaults.rb
        └── ....

我试图将 ActionController::HttpAuthentication::Token 包含在 defaults.rb 中,例如:

helpers do
  include ActionController::HttpAuthentication::Token

  def current_user
    return nil if headers['Authorization'].nil?

    @current_user ||= User.find_by_authentication_token(
      token_and_options(headers['Authorization'])
    )
  end

  def authenticate!
    error!('401 Unauthorized', 401) unless current_user
  end
end

但现在我得到:

 undefined method `authorization' for #<String:0x007ff51cdb85f8>

我必须添加一个自定义的 token_and_options 函数,它看起来像:

  def token_and_options(auth_string)
    if header = auth_string.to_s[/^Token (.*)/]
      values = .split(',').
        inject({}) do |memo, value|
          value.strip!
          key, value = value.split(/\=\"?/)
          value.chomp!('"')
          value.gsub!(/\\"/, '"')
          memo.update(key => value)
        end
      values.delete("token")
    end
  end

然后用类似的东西解析令牌:token_and_options(headers['Authorization'])

你走在正确的道路上:使用 token_params_from 并直接传递授权 header。

helpers do
  include ActionController::HttpAuthentication::Token

  def current_user
    return nil if headers['Authorization'].nil?

    @current_user ||= User.find_by_authentication_token(token)
  end

  def token
    token_params_from(headers['Authorization']).shift[1]
  end

  def authenticate!
    error!('401 Unauthorized', 401) unless current_user
  end
end

undefined method 异常是由于 token_and_options 期望 ActionDispatch::Request object 您提供的字符串。