19
19

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

DjangoでDiscordログインを実装する

Last updated at Posted at 2019-05-18

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ボタンから作成します。
スクリーンショット 2019-05-18 20.46.55.png

次に、表示された画面のCLIENT IDと CLIENT SECRETをメモしておきます。
スクリーンショット 2019-05-18 20.48.19.png

OAuth2を開き、REDIRECTSのAdd Redirectを押し、
http://127.0.0.1:8000/accounts/discord/login/callback/と入力します。
スクリーンショット 2019-05-18 23.22.18.png
そうしたら、 Save Changesを押し保存します。

Djangoでの設定

django-admin.pyもしくはPyCharmなどのツールを使い、djangoアプリケーションを作成します。(ここではプロジェクト名をappとします。)

django-admin.py startproject app

作成したら、app/settings.pyを開き、allauthの設定をします。

app/settings.py
INSTALLED_APPS = [
    # ...

    'django.contrib.sites',
    'allauth',
    'allauth.account',
    'allauth.socialaccount',
    'allauth.socialaccount.providers.discord',
]

...

SITE_ID = 1
app/urls.py
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を作成します。

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を編集します。

app/settings.py

...

ACCOUNT_ADAPTER = 'app.users.adapter.MyAccountAdapter'

リダイレクトがうまくいったかの確認のため、/でリダイレクトできるページを作成します。

app/urls.py
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
へ行き、先ほど作ったスーパーユーザーでログインします。

スクリーンショット 2019-05-18 21.26.07.png このような画面が表示されていると思います。 次に、`SOCIAL ACCOUNTS`の `Social applications`の `+Add`をクリックします。 スクリーンショット 2019-05-18 21.29.14.png

作成画面が表示されたら、以下の設定で保存してください。
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は何も書かないでください。

discord/provider.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]
discord/urls.py
from .provider import DiscordProvider
from allauth.socialaccount.providers.oauth2.urls import default_urlpatterns


urlpatterns = default_urlpatterns(DiscordProvider)
discord/views.py
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のアダプターを読み込みます。

app/settings.py

INSTALLED_APPS = [
    # 'allauth.socialaccount.providers.discord',
    'discord',
]

...

DISCORD_SCOPES = ['email', 'identify', 'connections', 'guilds', 'messages.read']

これで完成です。自分の好きなスコープを追加してください。

設定できるスコープの一覧

ここをクリックして表示

email

メールアドレスにアクセスします。

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
スクリーンショット 2019-05-19 0.44.41.png

DISCORD_SCOPES = ['email', 'identify', 'connections', 'guilds', 'messages.read']
スクリーンショット 2019-05-19 1.31.21.png

19
19
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
19
19

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?