pythonでTwitterのoauth認証部分を作成したのだが,少し手こずったのでメモっておく.
ちなみに,botを動かす場合のように,自分だけが認証をパスすればよい場合は簡単.
参考:TwitterBotの作成① - Hello World!!
今回は,Twitterクライアントなどのアプリケーションのように,それを使うユーザがそれぞれに認証を必要とする場合を想定している.
まず,認証の流れを示す.
Twitterのアプリを使用する時にこんなの1度は見たことあるはず.
http://www.dl.kuis.kyoto-u.ac.jp/~takemura/Twitter/oauth.cgi で実際に試せるよ.
具体的なoauth認証の流れを示す.
1. リクエストトークンの取得
まず,アプリを使いたいユーザが,そのアプリのConsumer keyとConsumer secretを用いて,リクエストを送る.
すると,Request token URL から,そのアプリをリクエストするための,Request tokenとRequest token secretが発行される.
2. アプリの認証
次に,このRequest tokenを用いて,Authorize URL でアプリの認証を行う.
ちなみに,このURLは,アプリを使う度に認証を必要とする.
実際のアプリでは,アプリを初めて使う時のみ認証して,2回目以降は認証を必要としない場合も多い.
このような実装を望む場合は,Authenticate URL で認証を行えばよい.
このURLでは,1回目のみ Authorize URL と同じ挙動をし,2回目以降は認証されているものとして自動でパスする.
3. コールバック
認証されると,認証後のトップページへコールバックされる.
ちなみに認証形式には2種類あり,PINという8文字の数字をユーザに手動で入力してもらわないといけないものと,指定されたページヘ自動で遷移(コールバック)するものとがある.
今回は後者を実装している.Webアプリでは後者が一般的だと思う.
前者でよいなら OAuth を使用して Twitter へ投稿する。 | Lonely Mobiler を参考にするとよい.
コールバック先のページは,アプリのページ(Twitter Developers)で指定できる.
何も指定しなければPIN入力形式となる.
コールバック時に,oauth_verifierという,認証をパスしたことを示す証明書が発行される.
4. アクセストークンの取得
oauth_verifierと,Request token,Request token secretを用いて,アクセストークンをリクエストする.
すると,Access token URL から,Access tokenとAccess token secretが発行される.
これでやっと終了.かなりめんどくさい…
このアクセストークンを用いて,ユーザのTwitterアカウントにアクセス可能になる.
以前までは,もっと単純に,ユーザのアカウントとパスワードを取得して認証するというBasic認証というものがあったのだが,セキュリティ上の問題のために,現在は廃止されている.
ちなみに,oauth認証で個人的にめんどくさかった点は,認証前に取得したRequest tokenとRequest token secretが,認証後にも必要となる点.
すなわち,Webページの遷移のため,セッションの管理が必要になる.
以下,プログラムを載せておく.
もし使いたい人がいれば,pika-shi/oauth · GitHub からダウンロードすればいいよ.
認証前
#!/usr/local/bin/python # -*- coding: utf-8 -*- import urllib import oauth2 as oauth import sqlite3 request_token_url = 'http://twitter.com/oauth/request_token' access_token_url = 'http://twitter.com/oauth/access_token' authenticate_url = 'http://twitter.com/oauth/authenticate' consumer_key = '**********' consumer_secret = '**********' def getOAuth(): consumer = oauth.Consumer(key=consumer_key, secret=consumer_secret) client = oauth.Client(consumer) # reqest_token を取得 resp, content = client.request(request_token_url, 'GET') request_token = dict(parse_qsl(content)) # 認証ページに遷移 url = '%s?oauth_token=%s' % (authenticate_url, request_token['oauth_token']) print '<meta http-equiv="refresh"content="1; url=%s">' % url # request_token と request_token_secret を保存 con = sqlite3.connect('oauth.db') con.execute(u'insert into oauth values (?, ?)', (request_token['oauth_token'], request_token['oauth_token_secret'])) con.commit() con.close() def parse_qsl(url): param = {} for i in url.split('&'): _p = i.split('=') param.update({_p[0]: _p[1]}) return param if __name__ == '__main__': print 'Content-type: text/html; charset: utf-8' print getOAuth()
認証後
#!/usr/local/bin/python # -*- coding: utf-8 -*- import os import cgi import cgitb import oauth2 as oauth import sqlite3 import twitter cgitb.enable() request_token_url = 'http://twitter.com/oauth/request_token' access_token_url = 'http://twitter.com/oauth/access_token' consumer_key = '**********' consumer_secret = '**********' def callback(): # oauth_token と oauth_verifier を取得 if 'QUERY_STRING' in os.environ: query = cgi.parse_qs(os.environ['QUERY_STRING']) else: query = {} # oauth_token_secret を取得 con = sqlite3.connect('oauth.db') oauth_token_secret = con.execute( u'select oauth_token_secret from oauth where oauth_token = ?' , [query['oauth_token'][0]]).fetchone()[0] con.close() # Access_token と access_token_secret を取得 consumer = oauth.Consumer(key=consumer_key, secret=consumer_secret) token = oauth.Token(query['oauth_token'][0], query['oauth_verifier'][0]) client = oauth.Client(consumer, token) resp, content = client.request(access_token_url, "POST", body="oauth_verifier=%s" % query['oauth_verifier'][0]) access_token = dict(parse_qsl(content)) return access_token['oauth_token'], access_token['oauth_token_secret'] def client(access_token, access_token_secret): api = twitter.Api(consumer_key=consumer_key, consumer_secret=consumer_secret, access_token_key=access_token, access_token_secret=access_token_secret, cache=None) TL = api.GetFriendsTimeline() for tweet in TL: print tweet.text.encode('utf-8') print '<br>' def parse_qsl(url): param = {} for i in url.split('&'): _p = i.split('=') param.update({_p[0]: _p[1]}) return param if __name__ == '__main__': print 'Content-type: text/html; charset: utf-8' print access_token, access_token_secret = callback() client(access_token, access_token_secret)
参考ページ
・tweepy と flask でwebアプリケーション認証 - 銀の人のメモ帳
・OAuth を使用して Twitter へ投稿する。 | Lonely Mobiler