2012-04-09 69 views
2

我試圖使用Python 3與Twitter的API接口返回鏈接頁面,讓我一個PIN碼,用來請求訪問令牌。詳細在這裏:https://dev.twitter.com/docs/auth/pin-based-authorization從Twitter的API獲取請求令牌與Python 3

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模塊的存在,它們有助於開發此模塊。但是,作爲一種學習體驗,我選擇不使用它們。

預先感謝您對我付出的時間和幫助。

+0

是否已確認這包Python3K的作品? – 2012-04-10 00:21:45

回答

7

的什麼我改變的概述:

  1. 我爲base64.standard_b64encode
  2. 換出binascii.b2a_base64我使用bytes.decode('ascii')方法轉換的字節串。 str()似乎將b附加到字符串。
  3. 我固定的參數以hmac.new - 這是KEY, MESSAGE,不MESSAGE, KEY
  4. PARAMETER_STRING刪除的參考include_entities - 如果你不要求使用include_entities(我相信這沒有意義對於令牌請求),它不能包含在PARAMETER_STRING中
  5. 我將oauth_callback=oob添加到PARAMETER_STRING的開頭 - 除了oauth_signature之外的所有oauth參數都必須包含在基本字符串中。
  6. 我改變了請求的部分來預先創建Request對象,然後添加Authorization頭部 - 您將Authorization頭部作爲HTTP主體發送。
  7. 要匹配此更改,我從HEADER_TITLE中刪除了尾隨分號。
  8. 我在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()) 
+0

幹得好,反應非常透徹。非常感謝你。在五小時時限到來的時候,我會獎勵賞金。 – 2012-04-15 16:37:24

0

看起來不像你的簽名基本字符串是正確的。基本上,就我所見,您不在基本字符串中包含任何參數。

上簽名鹼串的主題To quote the twitter docs

  1. 轉換的HTTP方法爲大寫和設置輸出字符串等於這個值。
  2. 將'&'字符附加到輸出字符串。
  3. Percent對URL進行編碼並將其附加到輸出字符串。
  4. 將'&'字符附加到輸出字符串。
  5. 百分比編碼參數字符串並將其附加到輸出字符串。

參數字符串反過來又使這樣的:(和我引述):

  1. 百分比編碼每一個關鍵,而將簽署價值。
  2. 按編碼密鑰按字母順序對參數列表進行排序。
  3. 對於每個鍵/值對:
  4. 附加編碼鍵碼來輸出字​​符串。
  5. 追加'='字符到輸出字符串。
  6. 將編碼後的值附加到輸出字符串。
  7. 如果存在剩餘的多個鍵/值對,追加一個「&」字符到所述輸出字符串。
+0

感謝您的回覆。我已更新我的代碼以將參數字符串追加到基本字符串,但它仍然不起作用。我想知道你是否不介意再看一眼呢? :) – 2012-04-14 21:36:39