I'm trying to integrate my Rails app with Aweber via OAuth, using the official aweber gem.
我正在尝试使用官方的aweber gem将我的Rails应用程序与Aweber通过OAuth集成。
If I follow their flow in the Rails console, I can get an access token, no problems:
如果我在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
Then I visit that URL, type in my credentials, get a verification code, and go back to the rails console:
然后我访问该URL,输入我的凭据,获取验证码,然后返回rails控制台:
oauth.authorize_with_verifier 'xxxxxx'
# => #<OAuth::AccessToken>
Success!
成功!
The problem is, I want to do this in the real world, not just at the console, which means my Ruby code needs to be broken up into two separate actions. First, there's the controller action which redirects to Aweber's Oauth page:
问题是,我想在现实世界中这样做,而不仅仅是在控制台上,这意味着我的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
Then there's the action which gets the access token after the user has input their credentials and been redirected:
然后是在用户输入其凭据并被重定向后获取访问令牌的操作:
def aweber_callback
oauth = AWeber::OAuth.new(ENV["AWEBER_CONSUMER_KEY"], ENV["AWEBER_CONSUMER_SECRET"])
oauth.authorize_with_verifier(params[:oauth_verifier])
end
When I do it this way, the final line (authorize_with_verifier
) always raises #<OAuth::Unauthorized: 401 Unauthorized>
.
当我这样做时,最后一行(authorize_with_verifier)总是引发#
Seems like the problem is that I'm initializing the oauth
variable twice, meaning I have two unrelated instances of AWeber::Oauth
... and only the instance of AWeber::Oauth that generated the authorize_url can get the access token. But I can't get the same instance in both aweber_callback
and aweber
because I'm dealing with two completely different threads and instances of the controller.
似乎问题是我正在初始化oauth变量两次,这意味着我有两个不相关的AWeber :: Oauth实例......并且只有生成authorize_url的AWeber :: Oauth实例才能获得访问令牌。但我无法在aweber_callback和aweber中获得相同的实例,因为我正在处理两个完全不同的线程和控制器实例。
When I inspect oauth
, I can see that the internal variables oauth.request_token.params["oauth_token"]
and oauth.request_token.params["oauth_token_secret"]
are different in each oauth
, which I'm guessing is the cause of the problem. I can get the 'correct' oauth_token
from the params (params[:oauth_token]
), but I can't figure out how to get the correct oauth_token_secret (not to mention that manually setting instance variables like this feels very hacky and is probably not the best approach.)
当我检查oauth时,我可以看到内部变量oauth.request_token.params [“oauth_token”]和oauth.request_token.params [“oauth_token_secret”]在每个oauth中是不同的,我猜这是问题的原因。我可以从params(params [:oauth_token])获得'正确'的oauth_token,但我无法弄清楚如何获得正确的oauth_token_secret(更不用说手动设置这样的实例变量感觉非常hacky并且可能不是最好的方法。)
How can I generate an access token?
如何生成访问令牌?
2 个解决方案
#1
6
I finally got this working by storing the oauth_token_secret
in the session. (And I have to say, I'm very unimpressed by Aweber's documentation and API setup. This took 10 times longer than it should have.)
我终于通过在会话中存储oauth_token_secret来实现这一点。 (而且我不得不说,我对Aweber的文档和API设置非常不满意。这比它应该的时间长10倍。)
Gemfile
的Gemfile
gem 'aweber', '~> 1.6.1', require: "aweber"
宝石'aweber','〜> 1.6.1',要求:“aweber”
Routes
路线
get "auth/aweber", to: "integrations#aweber", as: :aweber
get "auth/aweber/callback", to: "integrations#aweber_callback", as: :aweber_callback
Integrations Controller
集成控制器
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
The next step is to store access_token.token
and .secret
in my DB, then I'll be able to authorize users on future requests like this:
下一步是在我的数据库中存储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"...
I tried using the gem omniauth-aweber
in combination with the omniauth
gem, but I couldn't get it working (which is a shame, because I'm using other omniauth-xxx
gems in this app and it would have been nice to keep things consistent.) Basically, that gem automatically handles the /auth/aweber
part of the process, but after it redirects me back to /auth/aweber/callback/
I can't see any way to get the oauth_token_secret
- it's not in the request params, the session, or the cookies.
我尝试将gem omniauth-aweber与omniauth gem结合使用,但是我无法使它工作(这是一种耻辱,因为我在这个应用程序中使用其他omniauth-xxx宝石而且保留它会很好事情是一致的。)基本上,那个gem会自动处理进程的/ auth / aweber部分,但是在它重定向回到/ auth / aweber / callback /之后我看不到任何方法来获取oauth_token_secret - 它不在请求参数,会话或cookie。
I've answered my own question now but I'll give the bounty to anyone who can come up with an obvious improvement on the above, or figure out a way to make it all work with omniauth-aweber
.
我现在已经回答了我自己的问题,但是我会给那些能够对上述内容做出明显改进的人,或者想办法让这一切与omniauth-aweber一起工作。
#2
1
Reading through the AWeber API Ruby Library, this bit stands out
通过AWeber API Ruby Library阅读,这一点很突出
What if I don’t want to verify every time?
After verifying once, the oauth object contains an oauth.access_token.token and and oauth.access_token.secret which may be used to authorize your application without having to verify via url:
验证一次后,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
authorization can be performed as follows:
授权可以如下进行:
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)
So let's run through this:
让我们来看看:
You can create a class that keeps an object in memory for each User for enough time to finish the sign in and then save the token and secret for use until they expire.
您可以创建一个类,在每个用户的内存中保留一个对象足够的时间来完成登录,然后保存令牌和密码以供使用,直到它们过期。
Please note current_user is meant to be anything that uniquely identifies the user. You could use the session ID if your users aren't logged in yet at this point
请注意,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
With this class, your controller methods become:
使用此类,您的控制器方法将变为:
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
Please note that this is using low-level Rails caching. Make sure you set up your caching technique if you want something different from the default
请注意,这是使用低级Rails缓存。如果您需要与默认值不同的内容,请确保设置缓存技术
#1
6
I finally got this working by storing the oauth_token_secret
in the session. (And I have to say, I'm very unimpressed by Aweber's documentation and API setup. This took 10 times longer than it should have.)
我终于通过在会话中存储oauth_token_secret来实现这一点。 (而且我不得不说,我对Aweber的文档和API设置非常不满意。这比它应该的时间长10倍。)
Gemfile
的Gemfile
gem 'aweber', '~> 1.6.1', require: "aweber"
宝石'aweber','〜> 1.6.1',要求:“aweber”
Routes
路线
get "auth/aweber", to: "integrations#aweber", as: :aweber
get "auth/aweber/callback", to: "integrations#aweber_callback", as: :aweber_callback
Integrations Controller
集成控制器
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
The next step is to store access_token.token
and .secret
in my DB, then I'll be able to authorize users on future requests like this:
下一步是在我的数据库中存储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"...
I tried using the gem omniauth-aweber
in combination with the omniauth
gem, but I couldn't get it working (which is a shame, because I'm using other omniauth-xxx
gems in this app and it would have been nice to keep things consistent.) Basically, that gem automatically handles the /auth/aweber
part of the process, but after it redirects me back to /auth/aweber/callback/
I can't see any way to get the oauth_token_secret
- it's not in the request params, the session, or the cookies.
我尝试将gem omniauth-aweber与omniauth gem结合使用,但是我无法使它工作(这是一种耻辱,因为我在这个应用程序中使用其他omniauth-xxx宝石而且保留它会很好事情是一致的。)基本上,那个gem会自动处理进程的/ auth / aweber部分,但是在它重定向回到/ auth / aweber / callback /之后我看不到任何方法来获取oauth_token_secret - 它不在请求参数,会话或cookie。
I've answered my own question now but I'll give the bounty to anyone who can come up with an obvious improvement on the above, or figure out a way to make it all work with omniauth-aweber
.
我现在已经回答了我自己的问题,但是我会给那些能够对上述内容做出明显改进的人,或者想办法让这一切与omniauth-aweber一起工作。
#2
1
Reading through the AWeber API Ruby Library, this bit stands out
通过AWeber API Ruby Library阅读,这一点很突出
What if I don’t want to verify every time?
After verifying once, the oauth object contains an oauth.access_token.token and and oauth.access_token.secret which may be used to authorize your application without having to verify via url:
验证一次后,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
authorization can be performed as follows:
授权可以如下进行:
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)
So let's run through this:
让我们来看看:
You can create a class that keeps an object in memory for each User for enough time to finish the sign in and then save the token and secret for use until they expire.
您可以创建一个类,在每个用户的内存中保留一个对象足够的时间来完成登录,然后保存令牌和密码以供使用,直到它们过期。
Please note current_user is meant to be anything that uniquely identifies the user. You could use the session ID if your users aren't logged in yet at this point
请注意,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
With this class, your controller methods become:
使用此类,您的控制器方法将变为:
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
Please note that this is using low-level Rails caching. Make sure you set up your caching technique if you want something different from the default
请注意,这是使用低级Rails缓存。如果您需要与默认值不同的内容,请确保设置缓存技术