django-allauthを使いdjangoでdiscordアカウントでのログインを実装します。
今回のソースです。
https://github.com/sizumita/django-discord-allauth-test
(おまけまで全て含まれています。)
django-allauth
django上でソーシャルログインを実装できる拡張ライブラリです。
https://github.com/pennersr/django-allauth
なんとこちらがdiscordに対応していた!!
バージョン等
django==2.2.1
django-allauth==0.39.1
discord
言わずもがな、ゲーマー用ボイスチャットアプリです。
https://discordapp.com/
Installation
pipを使用してインストールします。(venv等を使用している場合は仮想環境に入っていることを確認してください。)
pip install django-allauth
Applicationの作成
https://discordapp.com/developers/applications/
へ飛び、Applicationを作成します。
右上にある New Application
を押し、Applicationの名前を入力し、Create
ボタンから作成します。
次に、表示された画面のCLIENT IDと CLIENT SECRETをメモしておきます。
OAuth2を開き、REDIRECTSのAdd Redirectを押し、
http://127.0.0.1:8000/accounts/discord/login/callback/
と入力します。
そうしたら、 Save Changesを押し保存します。
Djangoでの設定
django-admin.pyもしくはPyCharmなどのツールを使い、djangoアプリケーションを作成します。(ここではプロジェクト名をappとします。)
django-admin.py startproject app
作成したら、app/settings.py
を開き、allauthの設定をします。
INSTALLED_APPS = [
# ...
'django.contrib.sites',
'allauth',
'allauth.account',
'allauth.socialaccount',
'allauth.socialaccount.providers.discord',
]
...
SITE_ID = 1
from django.contrib import admin
from django.urls import path, include
urlpatterns = [
path('admin/', admin.site.urls),
path('accounts/', include('allauth.urls')),
]
以上を設定したら、ターミナルからmanage.pyと同じ階層に行き、マイグレート、スーパーユーザー作成をします。
./manage.py migrate
./manage.py createsuperuser
リダイレクトurlを指定する
初期設定だと/accounts/discord/login/callback
に飛ばされてしまうので、/
に飛ばす設定にします。
まず、app
ディレクトリ内にusers
ディレクトリを作成し、そこにadapter.py
を作成します。
from allauth.account.adapter import DefaultAccountAdapter
class MyAccountAdapter(DefaultAccountAdapter):
def __init__(self, request=None):
super().__init__(request)
def get_login_redirect_url(self, request):
# リダイレクトするurl
return 'http://127.0.0.1:8000/'
次に、settings.py
, urls.py
を編集します。
...
ACCOUNT_ADAPTER = 'app.users.adapter.MyAccountAdapter'
リダイレクトがうまくいったかの確認のため、/
でリダイレクトできるページを作成します。
from django.contrib import admin
from django.urls import path, include
from django.http import HttpResponse
urlpatterns = [
path('admin/', admin.site.urls),
path('accounts/', include('allauth.urls')),
path('', lambda request: HttpResponse('インデックス'), name='index'),
]
実はここでハマってました
discord側でエラーが起きて、どうしてなんだーと思って、djangoの方のログを追いかけてみたり、redirect urlを消したりしましたが、原因はdiscordの方のredirect urlをhttp://127.0.0.1:8000/accounts/discord/login/callback
にしていなかったのが原因でした。
Django起動
次に、djangoを起動します。
./manage.py runserver 8000
allauthの設定
http://127.0.0.1:8000/admin
へ行き、先ほど作ったスーパーユーザーでログインします。
作成画面が表示されたら、以下の設定で保存してください。
Provider
のDiscordを選択します。
Name
, Client id
, Secret key
にはdiscordの方で作成したApplicationのものを入れてください。
Sitesのexample.comをダブルクリックもしくはクリックした後に右矢印ボタンを押し、右側に移動させてください。
SAVEボタンを押し、作成します。
実際にログインしてみる
adminからログアウトし、 http://127.0.0.1:8000/accounts/discord/login へ行ってみましょう。
discordに飛び、ログインと認証ができ、認証が完了し、インデックスと表示されれば完了です!
最初の1、2回はエラーが発生したり、リダイレクトされなかったりしますが、何回かやるとなくなります。
さいごに
djangoでdiscordのログインをする方法を紹介しました。
allauthは初めて使いましたが、なかなか使いやすくてよかったです。
djangoでも簡単にdiscordログインが出来ました。
おまけ: 権限を変えてみる
初期設定だと権限が'email', 'identify'の二つしか許可されていないため、増やしてみたいと思います。
settingに書く方法がわからなかったため、同じものをもう一つ用意して、そちらを改造していきます。
discordのプロバイダーを自作する
まず、以下のファイル構成でdiscord
ディレクトリを作成します。
app
|
+-app/
|
+-discord/
|
+-manage.py
discord ディレクトリの中に、__init__.py
, provider.py
, urls.py
, views.py
を作成します。
__init__.py
は何も書かないでください。
from allauth.socialaccount.providers.base import ProviderAccount
from allauth.socialaccount.providers.oauth2.provider import OAuth2Provider
from django.conf import settings
class DiscordAccount(ProviderAccount):
def to_str(self):
dflt = super(DiscordAccount, self).to_str()
return self.account.extra_data.get('username', dflt)
class DiscordProvider(OAuth2Provider):
id = 'discord'
name = 'Discord'
account_class = DiscordAccount
def extract_uid(self, data):
return str(data['id'])
def extract_common_fields(self, data):
return dict(
email=data.get('email'),
username=data.get('username'),
name=data.get('username'),
)
def get_default_scope(self):
# ここを変更することでsettingから読み込めるようにする
return settings.DISCORD_SCOPES
provider_classes = [DiscordProvider]
from .provider import DiscordProvider
from allauth.socialaccount.providers.oauth2.urls import default_urlpatterns
urlpatterns = default_urlpatterns(DiscordProvider)
import requests
from .provider import DiscordProvider
from allauth.socialaccount.providers.oauth2.views import (
OAuth2Adapter,
OAuth2CallbackView,
OAuth2LoginView,
)
class DiscordOAuth2Adapter(OAuth2Adapter):
provider_id = DiscordProvider.id
access_token_url = 'https://discordapp.com/api/oauth2/token'
authorize_url = 'https://discordapp.com/api/oauth2/authorize'
profile_url = 'https://discordapp.com/api/users/@me'
def complete_login(self, request, app, token, **kwargs):
headers = {
'Authorization': 'Bearer {0}'.format(token.token),
'Content-Type': 'application/json',
}
extra_data = requests.get(self.profile_url, headers=headers)
return self.get_provider().sociallogin_from_response(
request,
extra_data.json()
)
oauth2_login = OAuth2LoginView.adapter_view(DiscordOAuth2Adapter)
oauth2_callback = OAuth2CallbackView.adapter_view(DiscordOAuth2Adapter)
settingの追記
app/settings.py
に、許可したいスコープの一覧のlistを書きます。また、自分で作成したdiscordのアダプターを読み込みます。
INSTALLED_APPS = [
# 'allauth.socialaccount.providers.discord',
'discord',
]
...
DISCORD_SCOPES = ['email', 'identify', 'connections', 'guilds', 'messages.read']
これで完成です。自分の好きなスコープを追加してください。
設定できるスコープの一覧
ここをクリックして表示
メールアドレスにアクセスします。
identify
ユーザー名とアバター画像にアクセスします。
connections
サードパーティのアプリケーションに接続します。
guilds
あなたがどのサーバーに入っているか確認します。
guilds.join
サーバーに参加します
- 招待を代わりに行います
gum.join
あなたの代わりにグループDMに参加します。
- これによりアプリはあなたに代わって作成されたグループDMに参加します。
rpc
Discordクライアントとインターフェイスで接続
- ローカルのdiscordクライアントとの接続を許可するアプリケーションです。
rpc.api
Discordクライアント上でアクションを実行してください。
- これにより、アプリがメッセージを送信すること、設定を変更することコマンドを実行することなどが可能になります。
rpc.notifications.read
Discordクライアントへの通知を受信する
- これにより、アプリはあなた宛の通知を見ることができます。
webhook.incoming
チャンネルにWebhookを追加します。
- アプリがチャンネルにメッセージを送信することを許可します。
messages.read
全てのメッセージを読み込む
- これによりアプリはあなたのアカウントがアクセスできる全てのメッセージを読むことができます。
applications.builds.upload
Upload and manage builds
applications.builds.read
Read build information
applications.store.update
Manage store SKUs, listings, and assets
applications.entitlements
Manage entitlements
- This allows the app to read and consume entitlements for applications as you on Discord's store
例
DISCORD_SCOPES = ['email', 'identify', 'connections', 'guilds', 'messages.read']