Rails - 通过 URL 请求在 Controller 中提交客户端和密码获取访问令牌

Rails - Get Access Token via URL Request submitting client and secret in Controller

我有一个可用的终端命令,它为我提供了一个 json,其中包含访问令牌(仅 X 分钟有效): curl -X POST -u [cliend_id]:[secret] "url_to_get_token"

我想要的是在我的控制器中动态生成访问令牌(并在我的会话中将其保存 X 分钟 - 但这只是一个加号)

我试过:exec("the terminal command") 这关闭了我的本地服务器,但通常是一个糟糕的解决方案。

有人知道解决办法吗?这应该是非常基础的,但我是 rails 新手。

非常感谢!

因为您可以获得调用 URL 的令牌,您需要做的是在 Rails 内使用任何 http 库执行相同的调用,而不是执行 exec 打电话。

我假设获取令牌是达到目的的一种手段,目的是在服务上执行某些操作,例如 "Get Elements",我将其称为 "My Service".我还假设 "My Service" 没有 已有 Ruby 个客户。如果您调用的服务有 Ruby 客户端,请使用它。

我是服务对象的捍卫者,所以我将提出一个解决方案,创建将从您的控制器调用的服务对象。

高级想法是有一个 MyServiceClient 对象,其中包含对您的服务执行操作的所有逻辑,包括获取令牌。还有一个模型,TokenStorage,只负责针对数据库存储和验证令牌。然后,SomeController 使用 MyServiceClientTokenStorage 对您的服务执行和验证操作。

像这样的分离使对象非常小,并且不会通过令牌轮换逻辑或有关 "My Service" 的内在细节污染您的控制器和模型。

# Gemfile

gem 'http'

# app/controllers/some_controller.rb

class SomeController < ActionController::Base
  def index
    @elements = my_service_client.get_elements
    # now the view will have access to the elements from your service
  end

  private

  def my_service_client
    @_my_service_client ||= MyServiceClient.new(TokenStorage)
  end
end

# app/models/token_storage.rb

class TokenStorage < ActiveRecord::Base
  def self.valid?
    expiration = select(:expiration).order(expiration: :desc).first
    expiration && Time.now < expiration
  end

  def self.token
    select(:token).order(expiration: :desc).first
  end

  def self.store(token, expiration)
    create(token: token, expiration: expiration)
  end
end

# lib/my_service_client.rb

require 'http'

class MyServiceClient
  def initialize(token_storage)
    @token_storage = token_storage
  end

  def get_elements
    HTTP.auth(token)
      .get(Config.my_service_url_to_get_elements)
  end

  private

  attr_reader :token_storage

  def token
    if token_storage.valid?
      token_storage.token
    else
      rotate_token
    end
  end

  def rotate_token
    token, expiration = create_token
    token_storage.store(token, expiration)
    token
  end

  def create_token
    parse_response(get_token_from_service)
  end

  def get_token_from_service
    # Try to store client_id and secret in environment variables rather than in
    # the codebase.
    HTTP.basic_auth(user: Config.my_service_client_id,
                    pass: Config.my_service_secret)
      .post(Config.my_service_url_to_get_token)
  end

  def parse_response(response)
    # Here you parse the response according to your interface, and get the token
    # value `token` and expiration date `expiration`.
    [token, expiration]
  end
end

您可以使用gem形式的准备决定。例如,devise.

或者如果你需要更轻量级的方式,你也可以使用authenticate_or_request_with_http_token,自己生成token。看看这个 link.