Я пытаюсь получить токен запроса Oauth из Twitter - я следую их руководству (ссылки ниже), и я прошел каждый шаг около 10 раз, но не могу понять, почему я получаю эту ошибку:

{\ "errors \": [{\ "code \": 32, \ "message \": \ "Не удалось аутентифицировать вас. \"}]}

Они используют Oauth 1.0. Я должен объединить все параметры, закодированные в процентах, в моем запросе, проценты закодировать их, добавить метод запроса (POST) и URL-адрес запроса, использовать его плюс мой секрет ключа api для создания подписи и добавить подпись к моему окончательный запрос на публикацию. Документы подписи находятся на этой странице и последующие документы запроса публикации находятся на этой странице . Я использовал пример кода, приведенный в руководстве, для создания подписи, и я получил тот же результат, что и руководство, поэтому я не думаю, что фактическое создание подписи является проблемой.

Я трижды проверил свой ключ API, секрет ключа API и URL-адрес обратного вызова.

Вот мой полный код. Может кто-нибудь видит проблему?

require 'net/http'
require 'uri'
require 'json'
require 'base64'
require 'cgi'
require 'openssl'

oauth_callback = "http://www.example.localhost:3000/twittercallback"
oauth_consumer_key = '[KEY]'
oauth_timestamp = Time.now.to_i
oauth_nonce = SecureRandom.hex(10) + oauth_timestamp.to_s
oauth_signature_method = "HMAC-SHA1"
oauth_version = "1.0"


one1 = CGI.escape "oauth_callback"
one2 = CGI.escape oauth_callback
two1 = CGI.escape "oauth_consumer_key"
two2 = CGI.escape oauth_consumer_key
three1 = CGI.escape "oauth_nonce"
three2 = CGI.escape oauth_nonce
four1 = CGI.escape "oauth_signature_method"
four2 = CGI.escape oauth_signature_method
five1 = CGI.escape "oauth_timestamp"
five2 = CGI.escape oauth_timestamp.to_s
six1 = CGI.escape "oauth_version"
six2 = CGI.escape oauth_version
string = "#{one1}=#{one2}&#{two1}=#{two2}&#{three1}=#{three2}&#{four1}=#{four2}&#{five1}=#{five2}&#{six1}=#{six2}"
encoded_string = CGI.escape string
url = "https://api.twitter.com/oauth/request_token"
encoded_url = CGI.escape url
encoded_string = "POST&" + encoded_url + "&" + encoded_string
signing_key = '[SECRET]'
encoded_signing_key = (CGI.escape signing_key) + "&"
digest = OpenSSL::Digest::Digest.new( 'sha1' )
hmac = OpenSSL::HMAC.digest( digest, encoded_signing_key, encoded_string)
signature = Base64.encode64( hmac ).chomp.gsub( /\n/, '' )

uri = URI.parse("https://api.twitter.com/oauth/request_token")
request = Net::HTTP::Post.new(uri)
request.content_type = "application/x-www-form-urlencoded"
oauth = 'OAuth oauth_callback="' + (CGI.escape oauth_callback) + '", oauth_nonce="' + (oauth_nonce + 'dsd') + '", oauth_signature_method="HMAC-SHA1", oauth_timestamp="' + oauth_timestamp.to_s + '", oauth_consumer_key="`<KEY>", oauth_signature="' + (CGI.escape signature) + '", oauth_version="1.0"'
request['Authorization'] = oauth
request.body = ""
req_options = {
    use_ssl: uri.scheme == "https",
}
response = Net::HTTP.start(uri.hostname, uri.port, req_options) do |http|
    http.request(request)
end

Вот мой заголовок request["Authorization"]

"OAuth oauth_callback = \" http% 3A% 2F% 2Fwww.example.localhost% 3A3000% 2Ftwittercallback \ ", oauth_nonce = \" e5686f142ca58a45af233fb6687667159245757549dsd \ ", oauthhot_time_sign =" \ " oauth_consumer_key = \ "[KEY] \", oauth_signature = \ "n9MNLO% 2Ft% 2FT6WX0Myu5JcTICXNAQ% 3D \", oauth_version = \ "1.0 \" "

И это пример заголовка из документации Twitter:

OAuth oauth_nonce = "K7ny27JTpKVsTgdyLdDfmQQWVLERj2zAK5BslRsqyw", oauth_callback = "HTTP% 3A% 2F% 2Fmyapp.com% 3A3005% 2Ftwitter% 2Fprocess_callback", oauth_signature_method = "HMAC-SHA1", oauth_timestamp = "1300228849", oauth_consumer_key = "OqEqJeafRSF11jBMStrZz", oauth_signature =» ПК% 2BMLdv028fxCErFyi8KXFM% 2BddU% 3D ", oauth_version =" 1.0 "

9
Joe Morano 15 Июн 2020 в 08:57

1 ответ

Лучший ответ

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

OAuth oauth_nonce="K7ny27JTpKVsTgdyLdDfmQQWVLERj2zAK5BslRsqyw",oauth_callback="http%3A%2F%2Fmyapp.com%3A3005%2Ftwitter%2Fprocess_callback",oauth_signature_method="HMAC-SHA1",oauth_timestamp="1300228849",oauth_consumer_key="OqEqJeafRSF11jBMStrZz",oauth_signature="Pc%2BMLdv028fxCErFyi8KXFM%2BddU%3D",oauth_version="1.0"

И укажите это в заголовке Authorization:

request['Authorization'] = <OAuth string>

В вашем коде есть много других проблем, из-за которых он не работает:

  • Неправильное экранирование параметров
  • Экранирование ключа подписи
  • Добавление dsd к nonce в заголовке Authorization
  • Неправильный порядок данных в заголовке авторизации (должен быть лексикографическим, например, для большинства библиотек в алфавитном порядке)

Таким образом, если мы переработаем ваш код, это приведет к следующему:

require 'net/http'
require 'uri'
require 'base64'
require 'cgi'
require 'openssl'
require 'securerandom'

oauth_consumer_key = CGI::escape('D6O7BIWc6MTgl0A8UaRRt83In')
oauth_timestamp = CGI::escape(Time.now.to_i.to_s)
oauth_nonce = CGI::escape(SecureRandom.hex(10) + oauth_timestamp.to_s)
oauth_signature_method = CGI::escape("HMAC-SHA1")
oauth_version = CGI::escape("1.0")

one1 = CGI::escape("oauth_consumer_key")
one2 = oauth_consumer_key
two1 = CGI::escape("oauth_nonce")
two2 = oauth_nonce
three1 = CGI::escape("oauth_signature_method")
three2 = oauth_signature_method
four1 = CGI::escape("oauth_timestamp")
four2 = oauth_timestamp
five1 = CGI::escape("oauth_version")
five2 = oauth_version
string = "#{one1}=#{one2}&#{two1}=#{two2}&#{three1}=#{three2}&#{four1}=#{four2}&#{five1}=#{five2}"
encoded_string = CGI.escape string
url = "https://api.twitter.com/oauth/request_token"
encoded_url = CGI.escape url
encoded_string = "POST&" + encoded_url + "&" + encoded_string
signing_key = 'xJPBJ2OdV6nM8r9e6ZysbnHTrZYm4R7LaY9OafNNNY3BkT4Oym'
encoded_signing_key = signing_key + '&'
digest = OpenSSL::Digest.new( 'sha1' )
hmac = OpenSSL::HMAC.digest( digest, encoded_signing_key, encoded_string)
signature = Base64.encode64( hmac ).chomp.gsub( /\n/, '' )

uri = URI.parse("https://api.twitter.com/oauth/request_token")
request = Net::HTTP::Post.new(uri)
request.content_type = "application/x-www-form-urlencoded"
oauth = 'OAuth ' + one1 + '="' + oauth_consumer_key + '", ' + two1 + '="' + oauth_nonce + '", ' + CGI::escape('oauth_signature') + '="' + (CGI.escape signature) + '", ' + three1 + '="HMAC-SHA1", ' + four1 + '="' + oauth_timestamp.to_s  + '", ' + five1 + '="1.0"'
puts oauth
request['Authorization'] = oauth
request.body = ""
req_options = {
    use_ssl: uri.scheme == "https",
}
response = Net::HTTP.start(uri.hostname, uri.port, req_options) do |http|
    http.request(request)
end
puts response
puts response.body

Я также хотел бы дать вам способ лучше обрабатывать параметры для генерации base_string и header:

require 'net/http'
require 'uri'
require 'base64'
require 'cgi'
require 'openssl'
require 'securerandom'

oauth_consumer_key = '<KEY>'
oauth_consumer_secret = '<SECRET>'
oauth_consumer_secret += '&'
oauth_timestamp = Time.now.getutc.to_i.to_s
oauth_nonce = SecureRandom.hex(10) + oauth_timestamp
oauth_signature_method = "HMAC-SHA1"
oauth_version = "1.0"

url = "https://api.twitter.com/oauth/request_token"
uri = URI.parse(url)
params = {
  'oauth_consumer_key' => oauth_consumer_key,
  'oauth_nonce' => oauth_nonce,
  'oauth_signature_method' => oauth_signature_method,
  'oauth_timestamp' => oauth_timestamp.to_s,
  'oauth_version' => oauth_version
}

base_string = "POST&" + CGI::escape(url) + "&" + CGI::escape(params.sort.collect{ |k,v| "#{CGI::escape(k)}=#{CGI::escape(v)}" }.join('&'))
oauth_signature = Base64.encode64("#{OpenSSL::HMAC.digest('sha1', oauth_consumer_secret, base_string)}").chomp

params['oauth_signature'] = oauth_signature

uri = URI.parse(url)
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true

header = "OAuth " + params.sort.collect {|k,v| "#{CGI::escape(k)}=\"#{CGI::escape(v)}\""}.join(", ")
rsp, data = http.post(uri, nil, {'Authorization' => header })

puts rsp
puts rsp.body

Другое предложение - использовать существующий доступный гем OAuth. Когда вы используете эту хорошо известную библиотеку, вы также можете получить поддержку от Twitter.

gem install oauth
require 'oauth'

oauth_consumer = OAuth::Consumer.new("<KEY>", "<SECRET>", :site => "https://api.twitter.com")

access_token = OAuth::AccessToken.new(oauth_consumer)

request_token = access_token.request(:post, "/oauth/request_token")
rsp = request_token.body
puts rsp
6
rfkortekaas 22 Июн 2020 в 12:01