2012-04-09 4 views
2

私は、アクセストークンの要求に使用するピン番号を与えるページのリンクを返すために、Python 3をTwitter APIとのインターフェイスに使用しようとしています。私がPOST要求を適切に承認しなかったことを私に伝えて、401を返すことで私に言ってきました。私がbase64のHMAC署名を正しくエンコードしていないのはなぜですか?私が生成したPOSTリクエストの他の部分はすべて、正しいPOSTリクエストのサンプルに基づいて正しく表示されます。Python 3のTwitter APIからリクエストトークンを取得する

私はこれに取り組んで数日を過ごしました。私は誰かが最後の部分を過ぎて私を揺さぶるのを助けることを望んでいます。ここで

TwitterのAPIドキュメントの最も関連する部分です:

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()) 

最後に、私は私に注意してくださいしたいと思います:https://dev.twitter.com/docs/api/1/post/oauth/request_token

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

は、これは私が使用していたコードですこのための開発を支援するPython OAuthとTwitterモジュールの存在を認識しています。しかし、学習経験として、私はそれらを使用しないことを選択しています。

ご利用いただきありがとうございます。

+0

は、あなたがこのパッケージがPython3Kで動作することを確認したことがありますか? –

答えて

7

私が変更内容の概要:

  1. 私はbytes.decode('ascii')メソッドを使用して文字列にバイトを変換base64.standard_b64encode
  2. ためbinascii.b2a_base64をスワップアウト。 str()は文字列にbを追加しているようです。それはない、MESSAGE, KEY
  3. KEY, MESSAGEだ私はPARAMETER_STRINGinclude_entitiesへの参照を削除 - -
  4. は私がhmac.newにパラメータの順序を固定しますが、要求にinclude_entitiesを使用していない場合は(と私はそれは意味がないと考えていますトークン要求の場合は、それをPARAMETER_STRINGに含めないでください)
  5. PARAMETER_STRINGの先頭にoauth_callback=oobを追加しました。oauth_signature以外のすべてのoauthパラメータは、ベース文字列に含める必要があります。
  6. Requestオブジェクトを事前に作成するよう要求が行われたセクションを変更して、Authorizationヘッダーを追加しました.HTTP本文としてAuthorizationヘッダーを送信していました。
  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

よくできた、非常に徹底的な対応。どうもありがとうございました。私は5時間の時間制限が上がった瞬間に賞金を授与します。 –

0

署名ベースの文字列が正しいとは思われません。基本的には、私が見る限り、基本文字列にはパラメータを含めません。シグニチャベースストリングのトピックに関する

To quote the twitter docs

  1. この値に等しい出力文字列を大文字と設定するHTTPメソッドを変換。
  2. '&'文字を出力文字列に付加します。
  3. パーセントはURLをエンコードし、出力文字列に追加します。
  4. '&'文字を出力文字列に付加します。
  5. パーセントはパラメータ文字列をエンコードし、出力文字列に追加します。

パラメータ文字列はこのように作られた順番になります。(と私は引用しています):署名されます

  1. パーセントエンコードすべてのキーと値。
  2. パラメータのリストを、暗号化されたキーでアルファベット順にソートします。
  3. 各キーと値のペアについて:
  4. 出力文字列にエンコードされたキーを追加します。
  5. 出力文字列に '='文字を追加します。
  6. エンコードされた値を出力文字列に追加します。
  7. キー/値ペアがさらに残っている場合は、出力文字列に '&'文字を追加します。
+0

お返事ありがとうございます。基本文字列にパラメータ文字列を追加するコードを更新しましたが、まだ動作していません。あなたはそれをもう一度見ても構わないと思っていますか? :) –

関連する問題