Django から python-twitter で OAuth認証して Twitter APIを使ってみる
DjangoからTwitterアカウントにOAuth認証してTwitter API を利用しようと思う。
python-twitter を利用して容易に実現。。。と思いきや、若干はまったので、メモしておく。
やりたいことは、利用者の認証と、利用者のリソースへのTwitterAPI経由でのアクセス。
1.OAuthの基本的な流れ
まずは、利用者にTwitterのユーザー認証をさせたい。Twitterでは、認証にOAuthを利用している。OAuthによる認証のシーケンスは、以下のサイトがわかりやすい。
http://www.atmarkit.co.jp/fsecurity/rensai/digid01/02.html
下図でいうと、Resource Owner が、Twitterのユーザーであり、開発アプリケーションの利用者。OAuth Client が、開発アプリケーション、OAuth Server が Twitter となる。
認証までの流れを確認。
- <事前>: OAuth サーバーに、自身の情報を登録
- <フローの開始> Initiate: OAuth クライアント上に、「Facebook ID」でログインなどのボタンがあり、ユーザーがそれを押下することで開始。
- <認可のリクエスト> Authorization Request: OAuth クライアントは、OAuthサーバーへリダイレクト。(OAuthクライアントの識別情報を付与)
- <ユーザー認証とアクセス権付与> Authenticate User & Get Approval: OAuth サーバーはユーザーを認証し、OAuth クライアントへアクセス権を付与するかを確認。
- <認可レスポンス> Authrization Response: OAuth サーバーは、OAuthクライアントへリダイレクト。リダイレクトURLにはアクセス権限付与を示すトークンを含む。
- <アクセストークンとの交換> Obtain Access Token: OAuthクライアントは受け取ったトークンをAccess Token(アクセストークン 後にAPIアクセスを利用するときに用いる)と交換。
2.Twitterへのアプリケーションの登録
まず、事前処理として、Twitterに開発アプリケーションの登録を行う必要があり、上記 <認可レスポンス>でリダイレクトする先のURLを Callback URLに登録する。
3.python-twitter によるサンプル
例外処理などを取り除いて引用すると、以下のようになる。
# 1.認可リクエストとリダイレクトURLの取得 resp = oauth_client.fetch_request_token(REQUEST_TOKEN_URL) url = oauth_client.authorization_url(AUTHORIZATION_URL) # 2.指定URLでOAuthクライアントへ権限の付与 webbrowser.open(url) # 3.上記 1.で取得した結果から、oauth_token、oauth_token_secret を取得 oauth_client = OAuth1Session(consumer_key, client_secret=consumer_secret, resource_owner_key=resp.get('oauth_token'), resource_owner_secret=resp.get('oauth_token_secret'), verifier=pincode)
はまったのは、上記2. と 3. の間。
実際に実装するときには、
- 開発アプリケーションが、上記1.を実行し、取得した URLにユーザーをリダイレクト
- ユーザーはリダイレクト先で、開発アプリケーションに権限を与えると、OAuthサーバーであるTwitterが、上記で設定したCallback URL のクエリパラメータに oauth_token を付与して(oauth_token_secret は付与されない) リダイレクト
- 開発アプリケーションでリダイレクトされたURLから oauth_token を取り出して処理
という流れになるのだが、TwitterからリダイレクトされるURLのクエリパラメータには、oauth_token_secret が含まれない。1.の処理で、oauth_toke_secretは取得できるのだが。。。
そういうものなのか?何か違和感がある。。。
と、思って試行錯誤していたのだが、
http://pika-shi.hatenablog.com/entry/20120210/1328866010
ちなみに,oauth認証で個人的にめんどくさかった点は,認証前に取得したRequest tokenとRequest token secretが,認証後にも必要となる点.
すなわち,Webページの遷移のため,セッションの管理が必要になる.
そういうものみたいだ。なーんだ。
4.ということで実装してみる
4.1 フロー開始
アプリに、Twitterでログインボタンを置いてみます。
4.2 認可のリクエスト
(1) トークンを保持するためのモデルを用意
from django.db import models class OAuthTokenTemp(models.Model): ''' ''' oauth_token = models.CharField(max_length=255, db_index=True, unique=True) oauth_token_secret = models.CharField(max_length=255, db_index=True, unique=True)
(2) 実装
- Twitterでログインボタンがおされたら、以下の関数を呼び出して、リダイレクト先のURLを取得します。
- CONSUMER_KEY と CONSUMER_SECRET は、Twitterアプリを登録すると発行される値を使用。
- 例外処理とかは、とりあえず省いているため適宜おこなう。
- 取得したoauth_token,oauth_token_secret をDBに保持。
- 取得したURLへ何らかの方法でリダイレクト。
import twitter from requests_oauthlib import OAuth1Session _CONSUMER_KEY = '*****************' _CONSUMER_SECRET = '*****************' REQUEST_TOKEN_URL = 'https://api.twitter.com/oauth/request_token' AUTHORIZATION_URL = 'https://api.twitter.com/oauth/authorize' def authorization_request(): ''' 認可のリクエストを行いTwitter認証ページへのURLを取得 ''' oauth_client = OAuth1Session(_CONSUMER_KEY, client_secret=_CONSUMER_SECRET) try: resp = oauth_client.fetch_request_token(REQUEST_TOKEN_URL) oauth = OAuthTokenTemp(oauth_token=resp.get('oauth_token'), oauth_token_secret=resp.get('oauth_token_secret')) oauth.save() except ValueError, e: print e return return oauth_client.authorization_url(AUTHORIZATION_URL)
4.3 ユーザー認証とアクセス権付与
Twitter 側でユーザー認証と、アプリに対する権限付与を行ってくれます。
4.4 認可レスポンス
連携アプリを認証するとたとえば、以下のような URLにリダイレクトされます。
- クエリパラメータに oauth_token が含まれるので、先ほど保存したDBを検索し、oauth_token_secretを取得する。
- 同じくクエリパラメータのoauth_verifire も含め、セッションを開始するパラメータがそろうので、セッションを開始し、アクセストークンを取得
- これでAPIが利用できるようになるため、ユーザー情報(下例 tw_user)を取得してみる。
from django.http import HttpResponse import twitter from requests_oauthlib import OAuth1Session _CONSUMER_KEY = '****************************' _CONSUMER_SECRET = ''****************************' ACCESS_TOKEN_URL = 'https://api.twitter.com/oauth/access_token' def twitter_auth(request): ''' Twitter認証を行う ''' oauth_token = request.GET["oauth_token"] oauth_verifier = request.GET["oauth_verifier"] oauth = OAuthTokenTemp.objects.get(oauth_token=oauth_token) oauth_token_secret = oauth.oauth_token_secret oauth_client = OAuth1Session(_CONSUMER_KEY, client_secret=_CONSUMER_SECRET, resource_owner_key=oauth_token, resource_owner_secret=oauth_token_secret, verifier=oauth_verifier) try: resp = oauth_client.fetch_access_token(ACCESS_TOKEN_URL) except ValueError, e: return api = twitter.Api(consumer_key=_CONSUMER_KEY, consumer_secret=_CONSUMER_SECRET, access_token_key=resp.get('oauth_token'), access_token_secret=resp.get('oauth_token_secret')) tw_user = api.VerifyCredentials() oauth.delete() :
https://dev.twitter.com/oauth/overview/faq
How long does an access token last?
We do not currently expire access tokens.
Your access token will be invalid if a user explicitly rejects
your application from their settings or if a Twitter admin suspends your application.
If your application is suspended there will be a note on your application page
saying that it has been suspended.
ここで、取得したアクセストークンは、アプリケーションが破棄しなければ、再利用できるようなので、開発アプリのユーザー情報に保持しておき、再度APIを呼び出すときに利用する。
4.5 成功!
ということで、上記手順にて、Twitterのユーザー情報から写真と名前を取得することができ、画面に表示できました。
めでたしめでたし。