10

我正在尝试使用官方 aweber gem通过 OAuth 将我的 Rails 应用程序与 Aweber 集成。

如果我在 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) 总是 raise #<OAuth::Unauthorized: 401 Unauthorized>

似乎问题在于我将oauth变量初始化了两次,这意味着我有两个不相关的AWeber::Oauth... 实例,并且只有生成 authorize_url 的 AWeber::Oauth 实例才能获取访问令牌。但是我无法在两者中获得相同的实例,aweber_callback因为aweber我正在处理两个完全不同的线程和控制器实例。

当我检查时oauth,我可以看到每个内部变量oauth.request_token.params["oauth_token"]oauth.request_token.params["oauth_token_secret"]不同oauth,我猜这是问题的原因。我可以oauth_token参数(params[:oauth_token]

如何生成访问令牌?

4

2 回答 2

7

我终于通过将 存储oauth_token_secret在会话中来完成这项工作。(我不得不说,我对 Aweber 的文档和 API 设置非常不满意。这比它应该花费的时间长了 10 倍。)

宝石文件

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"...

我尝试将 gemomniauth-aweber与 gem 结合使用omniauth,但我无法让它工作(这很遗憾,因为我omniauth-xxx在这个应用程序中使用了其他 gem,保持一致会很好。)基本上,那gem 会自动处理该/auth/aweber过程的一部分,但是在将我重定向回之后,/auth/aweber/callback/我看不到任何获取方法oauth_token_secret- 它不在请求参数、会话或 cookie 中。

我现在已经回答了我自己的问题,但我会将赏金奖励给任何可以对上述内容提出明显改进的人,或者想办法让它与omniauth-aweber.

于 2015-05-12T05:27:04.210 回答
1

通读 AWeber API Ruby Library,这一点很突出

如果我不想每次都验证怎么办?

验证一次后,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 是指唯一标识用户的任何东西。如果您的用户此时尚未登录,您可以使用会话 ID

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 缓存。如果您想要与默认设置不同的东西,请确保设置您的缓存技术

于 2015-05-12T04:35:15.340 回答