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 となる。

認証までの流れを確認。

  1. <事前>: OAuth サーバーに、自身の情報を登録
  2. <フローの開始> Initiate: OAuth クライアント上に、「Facebook ID」でログインなどのボタンがあり、ユーザーがそれを押下することで開始。
  3. <認可のリクエスト> Authorization Request: OAuth クライアントは、OAuthサーバーへリダイレクト。(OAuthクライアントの識別情報を付与)
  4. <ユーザー認証とアクセス権付与> Authenticate User & Get Approval: OAuth サーバーはユーザーを認証し、OAuth クライアントへアクセス権を付与するかを確認。
  5. <認可レスポンス> Authrization Response: OAuth サーバーは、OAuthクライアントへリダイレクト。リダイレクトURLにはアクセス権限付与を示すトークンを含む。
  6. <アクセストークンとの交換> Obtain Access Token: OAuthクライアントは受け取ったトークンをAccess Token(アクセストークン 後にAPIアクセスを利用するときに用いる)と交換。

zu02

2.Twitterへのアプリケーションの登録

https://apps.twitter.com/

まず、事前処理として、Twitterに開発アプリケーションの登録を行う必要があり、上記 <認可レスポンス>でリダイレクトする先のURLを Callback URLに登録する。

twitter_app_callback

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. 開発アプリケーションが、上記1.を実行し、取得した URLにユーザーをリダイレクト
  2. ユーザーはリダイレクト先で、開発アプリケーションに権限を与えると、OAuthサーバーであるTwitterが、上記で設定したCallback URL のクエリパラメータに oauth_token を付与して(oauth_token_secret は付与されない) リダイレクト
  3. 開発アプリケーションでリダイレクトされた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でログインボタンを置いてみます。

login_by_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 側でユーザー認証と、アプリに対する権限付与を行ってくれます。

twitter_user_approval

4.4 認可レスポンス

連携アプリを認証するとたとえば、以下のような URLにリダイレクトされます。

http://test.phraseit.info?oauth_token=5wFYbG7CyxNyJYkcZ6Edurf7BPJ8iYzm&oauth_verifier=vT0pBegUKQJyMU7Q0ErLSRU6ZLXHEe0D

  • クエリパラメータに 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のユーザー情報から写真と名前を取得することができ、画面に表示できました。

めでたしめでたし。

twitter_access_success

Follow me!

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です