Как подключить Aweber к моему Rails-приложению, используя OAuth?

Я пытаюсь интегрировать приложение Rails с Aweber через OAuth, используя официальный авебер-жемчуг.

Если я следую их потоку в консоли Rails, я могу получить токен доступа, никаких проблем:

oauth = AWeber::OAuth.new(ENV["AWEBER_CONSUMER_KEY"], ENV["AWEBER_CONSUMER_SECRET"])
puts oauth.request_token.authorize_url
# => https://auth.aweber.com/1.0/oauth/authorize?oauth_token=xxxxxxxxxxxxxx

Затем я нахожу этот URL-адрес, введите свои учетные данные, получу код подтверждения и вернусь к консоли rails:

oauth.authorize_with_verifier 'xxxxxx'
# => #<OAuth::AccessToken>

Успех!

Проблема в том, что я хочу сделать это в реальном мире, а не только на консоли, что означает, что мой код Ruby нужно разбить на два отдельных действия. Во-первых, есть действие контроллера, которое перенаправляется на страницу Aweber Oauth:

def aweber
  oauth = AWeber::OAuth.new(ENV["AWEBER_CONSUMER_KEY"], ENV["AWEBER_CONSUMER_SECRET"])
  redirect_to  oauth.request_token(oauth_callback: "http://127.0.0.1:3000/auth/aweber/callback").authorize_url
end

Затем появляется действие, которое получает токен доступа после того, как пользователь вводит свои учетные данные и перенаправляется:

def aweber_callback
  oauth = AWeber::OAuth.new(ENV["AWEBER_CONSUMER_KEY"], ENV["AWEBER_CONSUMER_SECRET"])
  oauth.authorize_with_verifier(params[:oauth_verifier]) 
end

Когда я делаю это так, конечная строка (authorize_with_verifier) всегда поднимает #<OAuth::Unauthorized: 401 Unauthorized>.

Похоже, проблема в том, что я инициализирую переменную oauth дважды, то есть у меня есть два несвязанных экземпляра AWeber::Oauth... и только экземпляр AWeber:: Oauth, сгенерированный authorize_url. получить токен доступа. Но я не могу получить один и тот же экземпляр как в aweber_callback, так и aweber, потому что я имею дело с двумя совершенно разными потоками и экземплярами контроллера.

Когда я проверяю oauth, я вижу, что внутренние переменные oauth.request_token.params["oauth_token"] и oauth.request_token.params["oauth_token_secret"] различаются в каждом oauth, который, как я предполагаю, является причиной проблемы. Я могу получить "правильный" oauth_token из параметров (params[:oauth_token]), но я не могу понять, как получить правильный файл oauth_token_secret (не говоря уже о том, что вручную настраиваемые переменные экземпляра, такие как это чувствует очень хаки и, вероятно, не самый лучший подход.)

Как я могу создать токен доступа?

Ответ 1

Наконец, я получил эту работу, сохранив oauth_token_secret в сеансе. (И я должен сказать, что я очень не впечатлен документацией Aweber и настройкой API. Это заняло 10 раз дольше, чем должно было быть.)

Gemfile

gem 'aweber', '~> 1.6.1', require: "aweber"

Маршруты

get "auth/aweber", to: "integrations#aweber", as: :aweber
get "auth/aweber/callback", to: "integrations#aweber_callback", as: :aweber_callback

Контроллер интеграции

def aweber
  oauth = get_aweber_oauth

  request_token = oauth.request_token(oauth_callback: aweber_redirect_uri)
  session[:aweber_oauth_token_secret] = request_token.secret

  redirect_to request_token.authorize_url
end


def aweber_callback
  oauth = get_aweber_oauth

  oauth.request_token = OAuth::RequestToken.from_hash(
    oauth.consumer,
    oauth_token: params[:oauth_token],
    oauth_token_secret: session[:aweber_oauth_token_secret],
  )

  access_token = oauth.authorize_with_verifier(params[:oauth_verifier])

  # TODO save access_token.token and access_token.secret
end

private

def get_aweber_oauth
  AWeber::OAuth.new(ENV["AWEBER_CONSUMER_KEY"], ENV["AWEBER_CONSUMER_SECRET"])
end

def aweber_redirect_uri
  @_aweber_callback_uri ||= begin
    if Rails.env.production?
      redirect_host = "http://myproductionurl.com"
    else
      redirect_host = "http://127.0.0.1:3000"
    end
    "#{redirect_host}#{Rails.application.routes.url_helpers.aweber_callback_path}"
  end
end

Следующий шаг - сохранить access_token.token и .secret в моей БД, то я смогу разрешить пользователям следующие запросы:

oauth = AWeber::OAuth.new(ENV["AWEBER_CONSUMER_KEY"], ENV["AWEBER_CONSUMER_SECRET"])
oauth.authorize_with_access(current_user.aweber_token, current_user.aweber_secret)
aweber = AWeber::Base.new(oauth)
# Make calls using "aweber"...

Я попытался использовать драгоценный камень omniauth-aweber в сочетании с драгоценным камнем omniauth, но я не смог заставить его работать (что является позором, потому что я используя другие omniauth-xxx драгоценные камни в этом приложении, и было бы неплохо сохранить согласованность.) В принципе, этот камень автоматически обрабатывает часть процесса /auth/aweber, но после того, как он перенаправляет меня обратно на /auth/aweber/callback/, я могу 't видеть любой способ получить oauth_token_secret - это не в параметрах запроса, сеансе или файлах cookie.

Теперь я ответил на свой вопрос, но я дам награду всем, кто может придумать очевидное улучшение выше, или выяснить способ заставить все это работать с omniauth-aweber.

Ответ 2

Чтение через Ruby Library API AWeber, этот бит выделяется

Что делать, если я не хочу проверять каждый раз?

После проверки один раз объект oauth содержит oauth.access_token.token и oauth.access_token.secret, которые могут использовать для авторизации вашего приложения без проверки через URL:

... oauth.authorize_with_verifier('verification_code') puts 'Access
token: ' + oauth.access_token.token puts 'Access token secret: ' +
oauth.access_token.secret The token and secret can then be saved, and

авторизация может выполняться следующим образом:

require 'aweber'
oauth = AWeber::OAuth.new('consumer_key', 'consumer_secret')
#Rather than authorizing with the verification code, we use the token and secret 
oauth.authorize_with_access(YOUR_ACCESS_TOKEN, YOUR_ACCESS_TOKEN_SECRET) 
aweber = AWeber::Base.new(oauth)

Итак, давайте пропустим это:

Вы можете создать класс, который хранит объект в памяти для каждого пользователя в течение достаточно времени, чтобы закончить вход, а затем сохранить токен и секрет для использования до истечения срока их действия.

Обратите внимание, что current_user предназначен для всего, что однозначно идентифицирует пользователя. Вы можете использовать идентификатор сеанса, если ваши пользователи еще не вошли в систему в данный момент

class AWeberSignIn

    def self.start_signing user
        oauth = Rails.cache.fetch("#{user}/aweber", expires_in: 5.minutes) do
            AWeber::OAuth.new(ENV["AWEBER_CONSUMER_KEY"], ENV["AWEBER_CONSUMER_SECRET"])
        end
        oauth.request_token(oauth_callback: "http://127.0.0.1:3000/auth/aweber/callback").authorize_url
    end

    def self.authorize_with_verifier user, oauth_verifier
        oauth = Rails.cache.fetch("#{user}/aweber")
        oauth.authorize_with_verifier(oauth_verifier)
        [oauth.access_token.token, oauth.access_token.secret]
    end

    def self.get_base_from_token token, secret
        oauth = AWeber::OAuth.new(ENV["AWEBER_CONSUMER_KEY"], ENV["AWEBER_CONSUMER_SECRET"])
        oauth.authorize_with_access(token, secret)
        AWeber::Base.new(oauth)
    end
end

С помощью этого класса ваши методы управления становятся:

def aweber
  redirect_to  AWeberSignIn.start_signin current_user #Assuming you have a current_user helper. Use whatever gives you a unique value per user
end

def aweber_callback
  token, secret = AWeberSignIn.authorize_with_verifier(current_user, params[:oauth_verifier]) 
  #Do something with token and secret. Maybe save it to User attributes?
  #You can then use them to get a AWeber base object via AWeberSignIn.get_base_from_token token, secret
end

Обратите внимание, что это использование кэширования с низким уровнем Rails. Убедитесь, что вы настроили свою технологию кэширования, если хотите что-то отличное от стандартного