我正在研究从Twitter上检索一些数据的Django应用程序,我需要手动处理请求,因为它的主要目的是让我们学习如何使用网络HTTP等协议。所以请不要建议我使用包装纸。
我的问题是每当我尝试请求初始请求令牌(使用此doc和here中引用的POST请求)时,我收到401:需要授权,我有不知道可能导致它的原因,因为我已经完全按照我所链接的文档所要求的格式包含了Authorization标题。在与urllib
合作时,我可能无法按照自己的意愿制作POST请求,或者在我签名/我放置的位置上可能存在错误它在标题中,即使在我看来应该没问题。
这是我的代码,用于处理请求"使用Twitter登录":
def sign(request):
url = 'https://api.twitter.com/oauth/request_token'
#I store consumer key, consumer secret and callback url in a txt
dir_path = path.dirname(path.realpath(__file__))
with open(path.join(dir_path, 'credentials.txt'), 'r') as TweetCred:
creds = TweetCred.read().split(linesep)
oauth_consumer_key = creds[0].split()[1]
oauth_callback = creds[1].split()[1]
consumer_secret = creds[2].split()[1]
oauth_nonce = ''.join(SystemRandom().choice(string.ascii_letters + string.digits) for _ in range(32))
#Desperate to understand what could be causing the error, I tried to use an integer timestamp sinceit was integer in the examples
oauth_timestamp = int(time.time())
parameter_string = ( 'oauth_nonce=' + urllib.parse.quote(oauth_nonce, safe='') +
'&oauth_callback=' + urllib.parse.quote(oauth_callback, safe='') +
'&oauth_signature_method=' + urllib.parse.quote('HMAC-SHA1', safe='') +
'&oauth_timestamp=' + urllib.parse.quote(str(oauth_timestamp), safe='') +
'&oauth_consumer_key=' + urllib.parse.quote(oauth_consumer_key, safe='') +
'&oauth_version=' + urllib.parse.quote('1.0', safe='')
)
sigbase = 'POST' + '&' + urllib.parse.quote(url, safe='') + '&' + urllib.parse.quote(parameter_string, safe='')
signkey = urllib.parse.quote(consumer_secret, safe='') + '&'
key = bytes(signkey, 'UTF-8')
base = bytes(sigbase, 'UTF-8')
digester = hmac.new(key, base, hashlib.sha1)
binsignature = digester.digest()
signature = urllib.parse.quote(base64.urlsafe_b64encode(binsignature), safe='')
oauth_header = ('Oauth ' + 'oauth_nonce="%s", ' % urllib.parse.quote(oauth_nonce, safe='') +
'oauth_callback="%s", ' % urllib.parse.quote(oauth_callback, safe='') +
'oauth_signature_method="%s", ' % urllib.parse.quote('HMAC-SHA1', safe='') +
'oauth_timestamp="%s", ' %urllib.parse.quote(str(oauth_timestamp), safe='') +
'oauth_consumer_key="%s", ' % urllib.parse.quote(oauth_consumer_key, safe='') +
'oauth_version="%s", ' % urllib.parse.quote('1.0', safe='') +
'oauth_signature="%s"' % signature
)
headers = {'Authorization': oauth_header}
#urllib wants a body to know that it's a POST, at least that's what the docs said, so I'm providing an empty one
values = {}
data = urllib.parse.urlencode(values).encode('ascii')
TokenRequest = urllib.request.Request(url, data, headers)
try:
print('opening request token url...')
with urllib.request.urlopen(TokenRequest) as response:
if response.getcode() != 200:
print('Response is %s' % response.getcode())
return HttpResponse('Error in getting the token from Twitter, please try again...')
body = loads(response.read())
if body['oauth_callback_confirmed'] != 'true':
print('oauth_callback not confirmed')
return HttpResponse('Error in getting the token from Twitter, please try again...')
oauth_token = body['oauth_token']
oauth_token_secret = body['oauth_token_secret']
except urllib.error.HTTPError as err:
#my program always ends up here, catches the exception and returns the line below
return HttpResponse('Error %s in getting the token from Twitter, please try again...' % err)
print('Successfully retrieved request token! Redirecting...')
loggee = User.objects.Create()
loggee.oauth_token = oauth_token
loggee.oauth_token_secret = oauth_token_secret
return HttpResponseRedirect('https://api.twitter.com/oauth/authenticate?oauth_token='+oauth_token)
任何帮助将不胜感激!我很匆忙,我真的无法绕过这个!
答案 0 :(得分:0)
在计算签名之前,您的签名基本字符串需要以书法形式排序(这意味着按字母顺序排列所有意图)(参考:Creating a signature)
因此您的参数字符串必须是:
parameter_string = (
'oauth_callback=' + urllib.parse.quote(oauth_callback, safe='') +
'&oauth_consumer_key=' + urllib.parse.quote(oauth_consumer_key, safe='') +
'&oauth_nonce=' + urllib.parse.quote(oauth_nonce, safe='') +
'&oauth_signature_method=' + urllib.parse.quote('HMAC-SHA1', safe='') +
'&oauth_timestamp=' + urllib.parse.quote(str(oauth_timestamp), safe='') +
'&oauth_version=' + urllib.parse.quote('1.0', safe='')
)