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
使用 MyServiceClient
和 TokenStorage
对您的服务执行和验证操作。
像这样的分离使对象非常小,并且不会通过令牌轮换逻辑或有关 "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.
我有一个可用的终端命令,它为我提供了一个 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
使用 MyServiceClient
和 TokenStorage
对您的服务执行和验证操作。
像这样的分离使对象非常小,并且不会通过令牌轮换逻辑或有关 "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.