使用Python 3从Twitter API检索请求令牌

时间:2012-04-09 23:51:02

标签: python oauth twitter twitter-oauth

我正在尝试使用Python 3与Twitter API进行交互,以返回页面的链接,该页面为我提供了用于请求访问令牌的密码。详见此处:https://dev.twitter.com/docs/auth/pin-based-authorization

Twitter的API回复我告诉我,我没有通过返回401来正确授权我的POST请求。我最好猜测为什么我没有正确编码base64中的HMAC签名。根据我查看的正确POST请求的样本,我生成的POST请求的其他部分看起来都是正确的。

我花了几天时间研究这个问题,我希望有人可以帮我推动我完成最后一部分。

以下是Twitter API文档中最相关的部分:https://dev.twitter.com/docs/api/1/post/oauth/request_token

https://dev.twitter.com/docs/auth/authorizing-request

这是我正在使用的代码:

import urllib.parse, urllib.request, json
from hashlib import sha1
import hmac
import binascii
import time
import random
import sys

#Server Links
REQUEST_URL = "https://api.twitter.com/oauth/request_token";
ACCESS_URL = "https://api.twitter.com/oauth/access_token";
AUTHORIZE_URL = "https://api.twitter.com/oauth/authorize";

#Consumer keys
TOKEN = "Omitted"
TOKEN_SECRET = "Omitted"

#Access keys
ACCESS_TOKEN = ""
ACCESS_TOKEN_SECRET = ""

TWEET = ""

count = 1

while len(sys.argv) > count:
    TWEET += sys.argv[count] + " "
    count += 1

TWEET = TWEET[:-1] #Get rid of trailing space

print(TWEET + "\n")

#Build content header for POST to return request tokens

HEADER_TITLE = "Authorization:"

#Consumer key
HEADER = 'OAuth oauth_callback="oob" oauth_consumer_key="' + TOKEN + '", '

#Nonce
HEADER += 'oauth_nonce="'
NONCE = ""
for i in range(32):
    NONCE += chr(random.randint(97, 122))
HEADER += NONCE
HEADER += '", '

#Timestamp
TIMESTAMP = str(int(time.time()))

#Signature
HEADER += 'oauth_signature="'
PARAMETER_STRING = "include_entities=true&oauth_consumer_key=" + TOKEN + "&oauth_nonce=" + NONCE + "&oauth_signature_method=HMAC-SHA1&oauth_timestamp=" + TIMESTAMP + "&oauth_version=1.0"
BASE_STRING = 'POST&' + urllib.parse.quote(REQUEST_URL, '') + '&' + urllib.parse.quote(PARAMETER_STRING, '')
SIGNING_KEY = urllib.parse.quote(TOKEN_SECRET, '') + '&'
print("DEBUG : SIGNING KEY " + SIGNING_KEY + " BASE STRING " + BASE_STRING + "\n")
HEADER += str(binascii.b2a_base64(hmac.new(BASE_STRING.encode(), SIGNING_KEY.encode(), sha1).digest()[:-1]))#Note to self, we may not want to remove the last character...
HEADER += '", '

#Signature Method
HEADER += 'oauth_signature_method="HMAC-SHA1", '

#Timestamp
HEADER += 'oauth_timestamp="' + TIMESTAMP + '", '

#Version
HEADER += 'oauth_version="1.0"'

print(HEADER_TITLE + "\n" + HEADER)

print(urllib.request.urlopen(urllib.request.Request(REQUEST_URL, bytes(HEADER_TITLE+HEADER, 'utf-8'))).read())

最后,我想指出,我知道Python OAuth和Twitter模块的存在有助于开发。但是,作为一种学习经历,我选择不使用它们。

非常感谢您的时间和帮助。

2 个答案:

答案 0 :(得分:9)

我改变的概述:

  1. 我为binascii.b2a_base64
  2. 换了base64.standard_b64encode
  3. 我使用bytes.decode('ascii')方法将字节转换为字符串。 str()似乎将b附加到字符串。
  4. 我将参数的顺序修改为hmac.new - 它是KEY, MESSAGE,而不是MESSAGE, KEY
  5. 我删除了对include_entitiesPARAMETER_STRING的引用 - 如果您未在请求中使用include_entities(我相信它对令牌请求没有意义),则一定不能包含在PARAMETER_STRING
  6. 我将oauth_callback=oob添加到PARAMETER_STRING的开头 - 所有oauth参数除了oauth_signature必须包含在基本字符串中。
  7. 我更改了请求的部分以预先创建Request对象,然后添加Authorization标头 - 您将Authorization标头作为HTTP正文发送。
  8. 为了匹配此更改,我从HEADER_TITLE
  9. 中删除了尾随分号
  10. 我在oauth_callback="oob"之后添加了缺少的分号。
  11. 享受!

    以下是您的代码的固定版本:

    import urllib.parse, urllib.request, json
    from hashlib import sha1
    import hmac
    import base64
    import time
    import random
    import sys
    
    #Server Links
    REQUEST_URL = "https://api.twitter.com/oauth/request_token";
    ACCESS_URL = "https://api.twitter.com/oauth/access_token";
    AUTHORIZE_URL = "https://api.twitter.com/oauth/authorize";
    
    #Consumer keys
    TOKEN = "Omitted"
    TOKEN_SECRET = "Omitted"
    
    #Access keys
    ACCESS_TOKEN = ""
    ACCESS_TOKEN_SECRET = ""
    
    TWEET = ""
    
    count = 1
    
    while len(sys.argv) > count:
    TWEET += sys.argv[count] + " "
    count += 1
    
    TWEET = TWEET[:-1] #Get rid of trailing space
    
    print(TWEET + "\n")
    
    #Build content header for POST to return request tokens
    
    HEADER_TITLE = "Authorization"
    
    #Consumer key
    HEADER = 'OAuth oauth_callback="oob", oauth_consumer_key="' + TOKEN + '", '
    
    #Nonce
    HEADER += 'oauth_nonce="'
    NONCE = ""
    for i in range(32):
    NONCE += chr(random.randint(97, 122))
    HEADER += NONCE
    HEADER += '", '
    
    #Timestamp
    TIMESTAMP = str(int(time.time()))
    
    #Signature
    HEADER += 'oauth_signature="'
    PARAMETER_STRING = "oauth_callback=oob&oauth_consumer_key=" + TOKEN + "&oauth_nonce=" + NONCE + "&oauth_signature_method=HMAC-SHA1&oauth_timestamp=" + TIMESTAMP + "&oauth_version=1.0"
    BASE_STRING = 'POST&' + urllib.parse.quote(REQUEST_URL, '') + '&' + urllib.parse.quote(PARAMETER_STRING, '')
    SIGNING_KEY = urllib.parse.quote(TOKEN_SECRET, '') + '&'
    print("DEBUG : SIGNING KEY " + SIGNING_KEY + " BASE STRING " + BASE_STRING + "\n")
    HEADER += urllib.parse.quote(base64.standard_b64encode(hmac.new(SIGNING_KEY.encode(), BASE_STRING.encode(), sha1).digest()).decode('ascii'))
    HEADER += '", '
    
    #Signature Method
    HEADER += 'oauth_signature_method="HMAC-SHA1", '
    
    #Timestamp
    HEADER += 'oauth_timestamp="' + TIMESTAMP + '", '
    
    #Version
    HEADER += 'oauth_version="1.0"'
    
    print(HEADER_TITLE + ":\n" + HEADER)
    
    HTTP_REQUEST = urllib.request.Request(REQUEST_URL)
    HTTP_REQUEST.add_header(HEADER_TITLE, HEADER)
    print(urllib.request.urlopen(HTTP_REQUEST, bytes('', 'ascii')).read())
    

答案 1 :(得分:0)

看起来您的签名基本字符串不正确。基本上,就我所见,你没有在基本字符串中包含任何参数。

关于签名基本字符串主题的

To quote the twitter docs

  
      
  1. 将HTTP方法转换为大写,并将输出字符串设置为等于此值。
  2.   
  3. 附加'&'输出字符串的字符。
  4.   
  5. 百分比对URL进行编码并将其附加到输出字符串。
  6.   
  7. 附加'&'输出字符串的字符。
  8.   
  9. 对参数字符串进行百分比编码并将其附加到输出字符串。
  10.   

参数字符串依次如下:(我在引用):

  
      
  1. 百分比编码将要签名的每个键和值。
  2.   
  3. 按编码键的字母顺序对参数列表进行排序。
  4.   
  5. 对于每个键/值对:
  6.   
  7. 将编码密钥附加到输出字符串。
  8.   
  9. 将'='字符附加到输出字符串。
  10.   
  11. 将编码值附加到输出字符串。
  12.   
  13. 如果剩余更多键/值对,请附加'&'输出字符串的字符。
  14.