前回の記事のつづきです。 kivantium.hateblo.jp
今回はTwitterでのOAuth認証を実装して、タイムラインを読み込むところまで進めます。
ライブラリのインストール
認証に必要なsocial-auth-app-django
というライブラリをインストールします。前回作ったプロジェクトのルートディレクトリで以下を実行します。
pipenv shell pipenv install social-auth-app-django
Twitterアプリケーションの作成
Twitter Developerのページからアプリを作成して、API keyとAPI secret keyを入手します。他に解説記事がたくさんあると思うので詳しくは書きません。
コールバックURLの追加
Twitterアプリケーションに適切なコールバックURLを設定しないと403エラーが出ます。今回のディレクトリ構成だと、ローカルで実行する場合は
http://localhost:8000/complete/twitter/
Herokuで実行する場合は
https://<appname>.herokuapp.com/complete/twitter/
を追加する必要があります。複数追加できるので両方追加しておくといいと思います。
設定の変更
playground/settings.py
を以下のように変更します。
(略) INSTALLED_APPS = [ 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', + 'hello', + 'social_django', ] (略) TEMPLATES = [ { 'BACKEND': 'django.template.backends.django.DjangoTemplates', 'DIRS': [], 'APP_DIRS': True, 'OPTIONS': { 'context_processors': [ 'django.template.context_processors.debug', 'django.template.context_processors.request', 'django.contrib.auth.context_processors.auth', 'django.contrib.messages.context_processors.messages', + 'social_django.context_processors.backends', + 'social_django.context_processors.login_redirect', ], }, }, ] (略) AUTH_PASSWORD_VALIDATORS = [ LANGUAGE_CODE = 'en-us' -TIME_ZONE = 'UTC' +TIME_ZONE = 'Asia/Tokyo' USE_I18N = True (略) STATIC_URL = '/static/' STATICFILES_STORAGE = 'whitenoise.storage.CompressedManifestStaticFilesStorage' +AUTHENTICATION_BACKENDS = [ + 'social_core.backends.twitter.TwitterOAuth', + 'django.contrib.auth.backends.ModelBackend', +] + +SOCIAL_AUTH_LOGIN_REDIRECT_URL = '/' + # Use different settings in local environment and Heroku # https://qiita.com/miler0528/items/1926e93ed97979f8e9fa (略) if not DEBUG: import django_heroku django_heroku.settings(locals()) + + SOCIAL_AUTH_TWITTER_KEY = os.environ['TWITTER_CONSUMER_KEY'] + SOCIAL_AUTH_TWITTER_SECRET = os.environ['TWITTER_CONSUMER_SECRET']
playground/local_settings.py
の末尾に以下の内容を追記します。
SOCIAL_AUTH_TWITTER_KEY = 'XXXXXXXXXXXXXXXXXXXXXXXXX' SOCIAL_AUTH_TWITTER_SECRET = 'XXXXXXXXXXXXXXXXXXXXXXXXX'
TWITTER_CONSUMER_KEY
とTWITTER_CONSUMER_SECRET
には先ほど作成したAPI keyおよびAPI secret keyを入れます。
設定を変更したのでマイグレートを行います。
python manage.py migrate
認証システムの実装
hello/urls.py
を以下のように変更してログアウト画面を追加します。
-from django.urls import path +from django.urls import path, include +import django.contrib.auth.views from . import views urlpatterns = [ path('', views.index, name='index'), + path('logout/', + django.contrib.auth.views.LogoutView.as_view(template_name = 'hello/logout.html'), + name='logout'), ]
playground/urls.py
に一行追記します。
urlpatterns = [
path('', include('hello.urls')),
+ path('', include('social_django.urls', namespace='social')),
]
hello/views.py
を次のように変更します。こうすることで、ログインしているかどうかでトップページにアクセスしたときの表示内容を変えることができます。
-from django.http import HttpResponse - +from django.shortcuts import render +from social_django.models import UserSocialAuth def index(request): - return HttpResponse("Hello, world!") + if request.user.is_authenticated: + user = UserSocialAuth.objects.get(user_id=request.user.id) + return render(request,'hello/index.html', {'user': user}) + else: + return render(request,'hello/index.html')
テンプレートの追加
テンプレートを入れるフォルダを作成します。
mkdir -p hello/templates/hello
hello/templates/hello/index.html
を以下の内容で作成します。
<html> <head> <title>index</title> </head> <body> {% if request.user.is_authenticated %} <p>あなたはログインしています (screen_name: {{ user.access_token.screen_name }})</p> <a href="/logout"><button type="button">ログアウト</button></a> {% else %} <p>あなたはログインしていません</p> <button type="button" onclick="location.href='{% url 'social:begin' 'twitter' %}'">Twitterでログイン</button> {% endif %} </body> </html>
hello/templates/hello/logout.html
を以下の内容で作成します。
<html> <head> <title>ログアウト</title> </head> <body> <p>ログアウトしました</p> <p><a href="/"><button type="button">トップへ</button></a></p> </body> </html>
以上の作業の結果、以下のようなディレクトリ構成になります。
playground/ ├── Pipfile ├── Pipfile.lock ├── Procfile ├── db.sqlite3 ├── hello │ ├── __init__.py │ ├── admin.py │ ├── apps.py │ ├── migrations │ │ └── __init__.py │ ├── models.py │ ├── templates │ │ └── hello │ │ ├── index.html │ │ └── logout.html │ ├── tests.py │ ├── urls.py │ └── views.py ├── manage.py ├── playground │ ├── __init__.py │ ├── asgi.py │ ├── local_settings.py │ ├── settings.py │ ├── urls.py │ └── wsgi.py └── runtime.txt
ローカルでのテスト
python manage.py runserver
ブラウザでhttp://localhost:8000/
にアクセスすると、ログインしていない場合の画面が表示されます。
「Twitterでログイン」ボタンを押すとこんな感じの認証画面に遷移します。
「連携アプリを認証」ボタンを押すと、ログインしてトップ画面に戻ります。ログインしている場合はscreen_nameが表示されます。
ログアウトボタンを押すとログアウトされます。
デプロイ
ローカル環境で正しく動いたらHerokuにデプロイします。
heroku config:set TWITTER_CONSUMER_KEY='XXXXXXXXXXXXXXXXXXXXXXXXX' heroku config:set TWITTER_CONSUMER_SECRET='XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX' git add . git commit -m 'Add login with Twitter' git push heroku master heroku run python manage.py migrate
https://<appname>.herokuapp.com/
にアクセスすると、ローカルと同じようなアプリが動くはずです。
タイムラインの読み込み
これでTwitter APIを使う準備が整ったので、試しにタイムラインの読み込みを行ってみます。 Twitter APIを扱うライブラリには以前の記事でも取り上げたtweepyを使うことにします。
tweepyのインストール
pipenv install tweepy
hello/views.py
の変更内容
from django.shortcuts import render from social_django.models import UserSocialAuth +from django.conf import settings + +import tweepy def index(request): if request.user.is_authenticated: user = UserSocialAuth.objects.get(user_id=request.user.id) - return render(request,'hello/index.html', {'user': user}) + consumer_key = settings.SOCIAL_AUTH_TWITTER_KEY + consumer_secret = settings.SOCIAL_AUTH_TWITTER_SECRET + access_token = user.extra_data['access_token']['oauth_token'] + access_secret = user.extra_data['access_token']['oauth_token_secret'] + auth = tweepy.OAuthHandler(consumer_key, consumer_secret) + auth.set_access_token(access_token, access_secret) + api = tweepy.API(auth) + timeline = api.home_timeline() + return render(request,'hello/index.html', {'user': user, 'timeline': timeline}) else: return render(request,'hello/index.html')
/hello/templates/hello/index.html
の変更内容
<body> {% if request.user.is_authenticated %} <p>あなたはログインしています (screen_name: {{ user.access_token.screen_name }})</p> + <ul> + {% for tweet in timeline %} + <li>@{{ tweet.user.screen_name }}: {{ tweet.text }}</li> + {% endfor %} + </ul> <a href="/logout"><button type="button">ログアウト</button></a> {% else %} <p>あなたはログインしていません</p>
変更をコミットしてgit push heroku master
でデプロイすると、タイムラインから最新20件のツイートを読み込んで表示することができるようになります。
次回はいつになるか分かりませんが、Twitterを使った何かしらのアプリを作ってみようと思います。