简体   繁体   中英

Encoding a GET using OAuth in Ruby Twitter API

I'm trying to write simple Ruby on Rails web app that logs in to Twitter via oAuth and gets the user's list of followers, without using an existing oAuth library . Using their guide at https://dev.twitter.com/docs/auth/oauth , I've managed to get logging in working correctly and thus have a subsequent outh_token and oauth_token_secret. However, when trying to encode the GET request for the logged in user's followers, I keep getting a 401 "This method requires authentication."

Using my code and their sample data, I can see that I'm generating the oauth_signature correctly. I may be generating the signature_base_string incorrectly, but seeing as it works ok when logging in, I don't see how it could be wrong the second time. The methods are part of a class, so the consumer key and secret are obviously class variables.

Relevant code is below. It's the output of the HTTP GET in 'followees' that's giving the 401. I'm hoping this is something ridiculously obvious that I'm just missing from looking at this too long! I know I have the right values passed to the function as parameters. Thanks.

  def followees(auth_token, auth_token_secret, user_id)
    method = 'GET'
    base_uri = 'https://api.twitter.com/1/friends/ids.json'
    params = {
      'cursor' => '-1',
      'oauth_consumer_key' => @@consumer_key,
      'oauth_nonce' => generate_nonce, #not shown, no need!
      'oauth_signature_method' => 'HMAC-SHA1',
      'oauth_token' => auth_token,
      'oauth_timestamp' => Time.now.to_i.to_s,
      'oauth_version' => '1.0',
      'user_id' => user_id
    }
    signature_base_string = signature_base_string(method, base_uri, params)
    params['oauth_signature'] = url_encode(sign(@@consumer_secret + '&' + auth_token_secret, signature_base_string))
    header = header(params)
    base_uri += '?cursor=-1&user_id=' + user_id
    url = URI.parse(base_uri)
    http = Net::HTTP.new(url.host, 443)
    http.use_ssl = true
    resp, data = http.get(url.path, { 'Authorization' => header })
  end

  def signature_base_string(method, uri, params)
    encoded_params = params.sort.collect{ |k, v| url_encode("#{k}=#{v}") }.join("%26")
    method + '&' + url_encode(uri) + '&' + encoded_params
  end

  def url_encode(string)
    CGI::escape(string)
  end

  def sign(key, base_string)
    digest = OpenSSL::Digest::Digest.new('sha1')
    hmac = OpenSSL::HMAC.digest(digest, key, base_string)
    Base64.encode64(hmac).chomp.gsub(/\n/, '')
  end

  def header(params)
    header = "OAuth "
    params.each do |k, v|
      header += "#{k}=\"#{v}\", "
    end
    header.slice(0..-3)
  end

Figured it out. Needed a break to step back from it! Basically, the last line in followees wasn't including the GET data, so

resp, data = http.get(url.path, { 'Authorization' => header })

should've been

resp, data = http.get(url.to_s, { 'Authorization' => header })

I had copied the code for POSTing, hence just url.path was being used there.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM