我正在连接到使用OAuth2进行身份验证的API(seek.com.au)。我在OAuth2 gem上挣扎了一段时间,最后我写下了普通的请求。虽然这很有效,但我仍然想了解我最初的OAuth2实现有什么问题。
这是我当前的工作代码,**第三方*涉及我使用可以访问其他帐户的帐户访问API的事实。此逻辑主要在scope
方法(在此代码段的底部)中实现。
以下内容包含一些额外的逻辑,但get_grant
和post_for_token
方法应包含所有内容。
module Seek::Base
CONFIG = YAML.load_file "#{Rails.root}/config/seek.yml"
HOST = 'http://test.api.seek.com.au/v1/'
REQUEST_URIS = {
get_grant: HOST + 'OAuth/auth',
post_for_token: HOST + 'OAuth/token',
get_applications: HOST + 'advertiser/applications'
}
def uri_for(request, params = {})
uri = REQUEST_URIS[request]
uri += '?' + params.to_param if params.any?
URI.parse uri
end
end
class Seek::OAuth2 # TODO? is instance needed?
include Seek::Base
# by account_id
@@tokens = {}
def initialize(account_id)
@account_id = account_id
end
def self.authenticate!(account_id)
new(account_id).authenticate!
end
# eg: when a request responded that the token is expired
def self.expire_token(account_id)
@@tokens.delete account_id
end
###########################################################################
############################### begin #####################################
# authentication
# see: http://developer.seek.com.au/docs/partner-api/api-methods/oauth-2.0
def authenticate!
@@tokens[@account_id] ||= begin
grant = get_grant
raise Exception.new(@error) if @error
Rails.logger.info "Retrive token for #{@account_id}"
post_for_token
end
end
private
# part of t he authentication process
# as we have one account for many entities, we use third party variation
# see: http://developer.seek.com.au/docs/partner-api/api-methods/oauth2/auth
def get_grant
uri = uri_for :get_grant, {response_type: :code, client_id: username, scope: scope}
response = Net::HTTP.get_response uri
params = response['location'].split('?').second
@error = params.split('error=').second
@grant_code = params.split('code=').second
end
# part of the authentication process
# see: http://developer.seek.com.au/docs/partner-api/api-methods/oauth2/token
def post_for_token
uri = uri_for :post_for_token
request = Net::HTTP::Post.new uri.path, {'Content-Type' => 'application/x-www-form-urlencoded;charset=UTF-8'}
request.set_form grant_type: :authorization_code, code: @grant_code, redirect_uri: ''
request.basic_auth username, password
response = Net::HTTP.new(uri.host, uri.port).request request
JSON(response.body)['access_token']
end
########################## end ############################################
###########################################################################
def username
CONFIG['credentials']['username']
end
def password
CONFIG['credentials']['password']
end
############## the scope method
############## I think I need to insert this in the OAuth request
def scope
"urn:seek:thirdparty:username:#{username},urn:seek:advertiser:identity:#{@account_id}"
end
end
以下是用于执行相同操作的几行(以替换authenticate!
方法),但遗憾的是,OAuth返回invalid_client
。
client = OAuth2::Client.new(username, password, :site => 'http://test.api.seek.com.au/v1')
client.auth_code.authorize_url redirect_uri: ''
token = client.auth_code.get_token 'authorization_code_value',
headers: {'Authorization' => %^Basic #{Base64.encode64 "#{username}:#{password}"}^ }
我认为问题依赖于OAuth创建的scope
方法(请参阅第一个代码段的底部),但我不确定,反正我无法找到修改它的方法。
我也开了an issue in GitHub,但我认为这已经涵盖了,只是没有记录(或者我找不到)。
答案 0 :(得分:1)
这个实现没有使用任何包装器,我尝试了gem OAuth2,但是我无法获得授权代码,
我认为,因为第三方实现需要自定义scope
我无法使用gem设置。
module Api::Base
CONFIG = YAML.load_file "#{Rails.root}/config/api.yml"
HOST = 'https://api.com.au/v1/'
REQUEST_URIS = {
get_grant: HOST + 'OAuth/auth',
post_for_token: HOST + 'OAuth/token',
get_applications: HOST + 'advertiser/applications'
}
def uri_for(request, params = {})
uri = REQUEST_URIS[request]
uri += '?' + params.to_param if params.any?
URI.parse uri
end
end
class Api::OAuth2
include Api::Base
# by account_id
@@tokens = {}
def initialize(account_id)
@account_id = account_id
end
def self.authenticate!(account_id)
new(account_id).authenticate!
end
# eg: when a request responded that the token is expired
def self.expire_token(account_id)
@@tokens.delete account_id
end
# authentication
def authenticate!
@@tokens[@account_id] ||= begin
grant = get_grant
raise StandardError.new(@error) if @error
puts "Retrive token for #{@account_id}"
post_for_token
end
end
private
# part of t he authentication process
# as we have one account for many entities, we use third party variation
def get_grant
uri = uri_for :get_grant, {response_type: :code, client_id: username, scope: scope}
http = Net::HTTP.new uri.host, uri.port
http.use_ssl = uri.port == 443
puts "SSL not set for uri #{uri}" unless http.use_ssl?
response = http.get uri.to_s
raise Exception.new(response.message) unless response.is_a? Net::HTTPFound
params = response['location'].split('?').second
@error = params.split('error=').second
@grant_code = params.split('code=').second
end
# part of the authentication process
def post_for_token
uri = uri_for :post_for_token
request = Net::HTTP::Post.new uri.path, {'Content-Type' => 'application/x-www-form-urlencoded;charset=UTF-8'}
request.set_form grant_type: 'authorization_code', code: @grant_code, redirect_uri: ''
request.basic_auth username, password
http = Net::HTTP.new uri.host, uri.port
http.use_ssl = uri.port == 443
response = http.start {|http| http.request request}
JSON(response.body)['access_token']
end
end
def username
CONFIG['credentials']['username']
end
def password
CONFIG['credentials']['password']
end
def scope
"urn:api:thirdparty:username:#{username},urn:api:advertiser:identity:#{@account_id}"
end
end
我仍然打算使用OAuth 2,I'll post my updates here if any