使用Python 3从Twitter API检索请求令牌
问题内容:
我正在尝试使用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模块。但是,作为学习经验,我选择不使用它们。
非常感谢您的时间和协助。
问题答案:
我所做的更改的概述:
- 我换出
binascii.b2a_base64
了base64.standard_b64encode
- 我使用该
bytes.decode('ascii')
方法将字节转换为字符串。str()似乎将b附加到字符串。 - 我将参数的顺序固定为
hmac.new
-而KEY, MESSAGE
不是MESSAGE, KEY
- 我删除了对
include_entities
in的引用PARAMETER_STRING
-如果您在请求中不使用include_entities(并且我认为对令牌请求没有意义),则不得将其包含在PARAMETER_STRING中 - 我
oauth_callback=oob
在开头添加了PARAMETER_STRING
-除oauth_signature之外的所有oauth参数都必须包含在基本字符串中。 - 我更改了发出请求的部分,以预先创建Request对象,然后添加Authorization标头-您正在将Authorization标头作为HTTP正文发送。
- 为了匹配此更改,我从中删除了结尾的分号
HEADER_TITLE
。 - 我在之后添加了缺少的分号
oauth_callback="oob"
。
请享用!
这是您的代码的固定版本:
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())