ローカル環境に Django プロジェクトを2つ作り、OAuth2で(ダミーの)プロフィール情報を取得するまで書きます。
2つの Django プロジェクトを作ります。test_provider, test_consumer です。
OAuth2の認証フローは、サーバ間通信のため「Authorization Code」形式で行います。
OAuth2についての情報は IPAのページ などにあります
Django プロジェクト 概要
test_provider
起動ポート 8000
ユーザーのIDとハッシュ化パスワードを保持します。
OAuth2 プロバイダを提供します。
ユーザーに test_provider への情報提供の認可を問います。
django-oauth-toolkit を使います
test_consumer
起動ポート 8001
ユーザーが最初にアクセスする Webページ
ユーザーに test_provider への認可ページへ誘導します。
ユーザー認可後は、このプログラムが test_provider へリクエストを行い、情報をもらいます。
django-allauth を使います。
※なお、django-allauth と同じくらい使いやすいのが python-social-auth です。Django のライブラリも含んでいます。
django-social-auth というライブラリも見かけると思いますが、Python3に対応していないのでやめておきましょう。
OAuth2プロバイダの開発
django-oauth-toolkit の素晴らしいドキュメントがここにあります。
「Make a Provider in a Minute」という挑発的なタイトルですが、
認証モデルにこだわりがなければほんとにすぐ作れます。
がんばっても1分では作れないと思いますが…。
Django プロジェクトの作成
$ mkdir test-oauth
$ cd test-oauth
$ django-admin.py startproject test_provider
$ pip install django-oauth-toolkit django-cors-headers
$ cd test_provider
test_provider/settings.py の編集
INSTALLED_APPS に追加
'oauth2_provider',
'corsheaders',
MIDDLEWARE_CLASSES に追加
'corsheaders.middleware.CorsMiddleware',
末尾に追加
CORS_ORIGIN_ALLOW_ALL = True
test_provider/urls.py の編集
from django.conf.urls import url, include
from django.contrib import admin
from .views import profile_view
urlpatterns = [
url(r'^admin/', admin.site.urls),
url(r'^o/', include('oauth2_provider.urls', namespace='oauth2_provider')),
url(r'^api/profile/$', profile_view, name='profile'),
url(r'^accounts/login/', 'django.contrib.auth.views.login', name='login',
kwargs={'template_name': 'admin/login.html'}),
]
test_provider/views.py の作成
from django.http import JsonResponse
from oauth2_provider.views.generic import ProtectedResourceView
class ProfileView(ProtectedResourceView):
def get(self, request, **kwargs):
user = request.resource_owner
return JsonResponse({
'user_id': user.id,
'email': user.email,
'date_joined': user.date_joined,
'secret_message': 'The quick brown fox',
})
profile_view = ProfileView.as_view()
DB に反映
$ ./manage.py migrate
Adminユーザーの作成
OAuthプロバイダを追加設定するためには、Adminユーザーが必要なため作っておきます。
$ ./manage.py createsuperuser
テストサーバの起動
$ ./manage.py runserver 8000
OAuthプロバイダの設定
プロバイダの設定ページにアクセスするために、一度 Admin サイトにログインしておきます。
Admin サイトにログイン後、アプリ追加ページを開きます。
http://127.0.0.1:8000/o/applications/
Click here をクリックします。
Register a new application ページとなるので、
Name: test-consumer (何でも良い)
Client type: Confidential
Authorization grant type: Authorization code
Redirect urls:
http://localhost:8001/accounts/testprovider/login/callback/
http://127.0.0.1:8001/accounts/testprovider/login/callback/
このように入力し、saveします。
作成した OAuthプロバイダは、このツールで簡単なテストができます。
client_id に先ほどの client_id をコピペし、
Authorization url は http://localhost:8000/o/authorize/ を入れればなんとなくのテストができます。
テストユーザーの作成
Admin から、テストユーザーを作っておきます。
http://127.0.0.1:8000/admin/auth/user/
ADD USER をクリックし、適当なユーザーを作っておいてください。
OAuth2 でのログイン時、このユーザーID/パスワードでログインを行うことになります。
引き続き、OAuthコンシューマの開発を行います。
起動中の Django テストサーバは、そのまま起動させっぱなしにしておいてください。
OAuth2コンシューマテストアプリの作成
Django プロジェクトの作成
$ cd test-oauth
$ django-admin.py startproject test_consumer
$ pip install django-allauth
$ cd test_consumer
ここでは、OAuth クライアントライブラリ django-allauth をインストールしています。
django-allauth は多彩はクライアント接続に対応した、多機能なライブラリで、django1.9 + Python 3.5 でも動きますので使い勝手が良いです。
設定
http://django-allauth.readthedocs.io/en/latest/installation.html
test_consumer/settings.py
TEMPLATES の OPTIONS の context_processors に追加
'django.template.context_processors.request',
Django 1.9 なら、デフォルトで入ってると思います。
INSTALLED_APPS に追加
'django.contrib.sites',
'test_consumer',
'allauth',
'allauth.account',
'allauth.socialaccount',
'allauth.socialaccount.providers.google',
'allauth.socialaccount.providers.twitter',
'testprovider', # これから作る
allauth.socialaccount.providers.* は任意に選んで追加してください。
テストのために google と twitter を追加しています。
どんなプロバイダが準備されているかは公式ドキュメントに書いてあります。
http://django-allauth.readthedocs.io/en/latest/installation.html
末尾に追加
AUTHENTICATION_BACKENDS = (
'django.contrib.auth.backends.ModelBackend',
'allauth.account.auth_backends.AuthenticationBackend',
)
SITE_ID = 1
SESSION_COOKIE_NAME = 'test-consumer-session-id'
test_consumer/urls.py
from django.conf.urls import url, include
from django.contrib import admin
from django.views.generic import TemplateView
urlpatterns = [
url(r'^admin/', admin.site.urls),
url(r'^$', TemplateView.as_view(template_name='index.html')),
url(r'^accounts/', include('allauth.urls')),
]
テンプレートの作成
$ mkdir test_consumer/templates
test_consumer/templates/index.html を作成
{% load socialaccount %}
{% load account %}
<html>
<head>
<meta charset="utf-8" />
</head>
<body>
<a href="{% provider_login_url "twitter" %}">Twitterでログイン</a><br />
<a href="{% provider_login_url "google" %}">Googleでログイン</a><br />
<a href="{% provider_login_url "testprovider" %}">Test Provider でログイン</a><br />
<hr />
{% if user.is_authenticated %}
ログインユーザー: {% user_display user %}<br />
{% for sa in user.socialaccount_set.all %}
{{ sa.extra_data }}<br />
{% endfor %}
{% endif %}
</body>
</html>
testprovider アダプタの作成
allauth に入っている、google のアダプタを改修して作るのが最も手軽でしょう。
allauth/socialaccount/providers/google このディレクトリをまるごとコピーし、
testprovider としてペーストします。 ( manage.py がいるディレクトリに)
内容は以下のようになります。
testprovider/provider.py
from allauth.socialaccount import providers
from allauth.socialaccount.providers.base import ProviderAccount
from allauth.socialaccount.providers.oauth2.provider import OAuth2Provider
class TestAccount(ProviderAccount):
def to_str(self):
dflt = super(TestAccount, self).to_str()
return self.account.extra_data.get('name', dflt)
class TestProvider(OAuth2Provider):
id = 'testprovider'
name = 'Test Provider'
account_class = TestAccount
def get_default_scope(self):
return ['read', 'write']
def get_site(self):
settings = self.get_settings()
return settings.get('SITE', 'testprovider')
def extract_uid(self, data):
uid = str(data['user_id'])
return uid
def extract_common_fields(self, data):
return dict(username=data.get('email', 'no name'))
providers.registry.register(TestProvider)
testprovider/urls.py
from allauth.socialaccount.providers.oauth2.urls import default_urlpatterns
from .provider import TestProvider
urlpatterns = default_urlpatterns(TestProvider)
testprovider/views.py
import requests
from allauth.socialaccount.providers.oauth2.views import (OAuth2Adapter,
OAuth2LoginView,
OAuth2CallbackView)
from allauth.socialaccount.providers import registry
from .provider import TestProvider
from django.conf import settings
server_url_prefix = getattr(
settings, 'TEST_PROVIDER_URL_PREFIX',
'http://127.0.0.1:8000')
class TestOAuth2Adapter(OAuth2Adapter):
provider_id = TestProvider.id
access_token_url = server_url_prefix + '/o/token/'
authorize_url = server_url_prefix + '/o/authorize/'
profile_url = server_url_prefix + '/api/profile/'
def complete_login(self, request, app, token, **kwargs):
provider = registry.by_id(app.provider)
resp = requests.get(self.profile_url,
params={'access_token': token.token})
extra_data = resp.json()
return self.get_provider().sociallogin_from_response(
request, extra_data)
oauth2_login = OAuth2LoginView.adapter_view(TestOAuth2Adapter)
oauth2_callback = OAuth2CallbackView.adapter_view(TestOAuth2Adapter)
DBのマイグレーション
$ ./manage.py migrate
Adminユーザーの作成
$ ./manage.py createsuperuser
テストサーバの起動
$ ./manage.py runserver 8001
アプリケーションの登録
http://127.0.0.1:8001/admin/
Admin サイトにログイン後、SOCIAL ACCOUNTS の Social applications の +Add をクリックします。
Provider: Test Provider
Name: Test Provider
Client id: 先ほどの 8000 admin で作った Client id
Secret key: 先ほどの 8000 admin で作った Secret key
Key: 空
Sites: example.com を選択
これで、Save します。
Google, Twitter など他サービスへのログインも必要であれば、ここから追加できます。
クライアントとしての動作テスト
先ほど、8000ポートにログインしたブラウザとは別のブラウザを使います。(ログアウト状態になっているため)
ここで、「Test Provider でログイン」をクリックします。
( AllAuth が自動的にログインフォームを提供してますので、このURLからでもいけます。/accounts/login/ )
そうすると、8000 ポートへ転送され、ログインフォームが出てきます。
今回は時間節約のため、Django Admin のログインフォームを流用していますが、
通常は自作のログインフォームをここで表示させることになると思います。
8000 (test_provider) で作ったテストユーザーでログインしてみましょう。
ログインが成功すると、認可を求めるページとなりますので、「Authorize」をクリック。
ちなみに、この認可を求めるページは、8000 (test_provider) の Admin の アプリ設定の、「Skip authorization」にチェックを入れると省略できます。
ログインに成功すると、8001 ポートに戻ってきます。
http://127.0.0.1:8001/accounts/profile/
が表示されますが、このページはまだ作っていませんので Not found になります。
情報取得は成功していますので、トップページのURLを手で入力して情報を見てみます。
http://127.0.0.1:8001/
トップページ下部に、API取得した extra_data を表示する箇所があります。
そこに、OAuth2 のプロバイダから取得した情報が表示されるのが確認できます。
OAuthプロバイダの /api/profile/ から取得した 'secret_message': 'The quick brown fox' が、OAuthコンシューマで取得できているのが確認できます。