401:从Twitter API检索请求令牌时需要授权

时间:2018-02-16 14:13:26

标签: python django twitter twitter-oauth

我正在研究从Twitter上检索一些数据的Django应用程序,我需要手动处理请求,因为它的主要目的是让我们学习如何使用网络HTTP等协议。所以请不要建议我使用包装纸。

我的问题是每当我尝试请求初始请求令牌(使用此dochere中引用的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)

任何帮助将不胜感激!我很匆忙,我真的无法绕过这个!

1 个答案:

答案 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='')
     )