简体   繁体   中英

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

I have a working terminal-command which provides me with an json containing the access token (which is valid only X-minutes): curl -X POST -u [cliend_id]:[secret] "url_to_get_token"

What I want is to generate the Access-Token dynamically in my Controller (and save it for X-minutes in my session - but this is only a plus)

I tried: exec("the terminal command") which shuts down my local server but is in general a bad solution.

Does anyone knows a solution? This should be very basic, but I am a rails newbe.

Thanks a lot in advance!

Since you can get the token calling a URL, what you have to do is to perform that same call but within Rails with any http library, instead of doing an exec call.

I'm assuming that getting the token is a means to an end, and that end is to perform some action, for example "Get Elements", on a service, which I'll call "My Service". I'm also assuming that "My Service" doesn't have a Ruby client already. If the service you're calling has a Ruby client, use it.

I'm a defender of Service Objects so I'll propose a solution creating Service Objects that will be called from your controller.

The high level idea is that there's a MyServiceClient object with all the logic to perform actions to your service, including getting the token. There's also a model, TokenStorage , responsible of only storing and validating tokens against the database. Then, SomeController uses MyServiceClient and TokenStorage to perform and validate actions against your service.

A separation like this keeps objects very small and doesn't pollute neither your controller nor your model with token rotation logic or intrinsic details about "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

You can use ready-decision in a form of gem. For example, devise .

Or if you need a more light-weighted approach, you can also use authenticate_or_request_with_http_token and generate token by yourself. Check out this link .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM