nikkie-ftnextの日記

イベントレポートや読書メモを発信

2020年積み残し解消:django-allauthを使ったソーシャルアカウント(GitHub・Slack)連携、素振りの記

はじめに

この記事はDjango Advent Calendar 2020 14日目の記事です。

頑張れば、何かがあるって、信じてる。nikkieです。
2020年はPyCon JPスタッフ活動の中で、力を付けたくてDjangoアプリを作りました。
Slackアカウントでアプリにログインする機能を実装する際に、素振り不足を理由にdjango-allauthの採用を見送りました。
これがちょっとした心残りとなっており、年内に解消すべくアドベントカレンダーの締切駆動でdjango-allauthを触ることにしました。

目次

経緯:積み残したdjango-allauth

※8月のPyCon JPで話した内容1と重なります。

PyCon JPスタッフ活動の中で、レビューに使うスタッフ内部用のWebアプリ2Djangoで実装しました。
スタッフだけがログインできるように、PyCon JP Slackのアカウントを使ってログインする機能を実装しました(スライド31〜33)。
実装中はdjango-allauthも候補にあったのですが、ドキュメントを見た感じすぐに使えるイメージがつかめず、別のパッケージを使いました。
「会期が終わった後に同じ実装をするならdjango-allauthを試したい」と思っていたので、今回試しました。
今回の素振りのゴールは、簡易的なアプリでdjango-allauthを使ってSlackアカウントログインを実装することです。
「レビューアプリにdjango-allauthを導入できそうという感触を持てたらいいな」と取り組みました。

開発環境

django-allauthPython 3.8までだったので、3.8を選択しました。

$ sw_vers
ProductName:    Mac OS X
ProductVersion: 10.14.6
BuildVersion:   18G4032
$ python -V
Python 3.8.6
$ pip install Django==3.1.4 django-allauth==0.44.0 django-environ==0.4.5

Django Girls Tutorialに沿ったディレクトリ構成で今回の練習用アプリを実装しています。
DBはsqliteを使い、ローカルでのみ動かしました。

リポジトリはこちらです。

素振り1:『現場で使えるDjangoの教科書 実践編』に沿ってGitHubアカウントでログイン

参考にしたのは、akiyokoさんの『現場で使えるDjangoの教科書 実践編』。

django-allauthはソーシャルアカウント連携だけではなく、allと名に負う通り、ログイン周り全般も面倒を見てくれます!
※ただし、今回はソーシャルアカウント連携に絞って見ていきます。

  1. settings.py を変更
  2. GitHubでOAuth Appを作成
  3. Django AdminからSocial applicationを作成

前提

前提として、以下の状態とします(Django Girls Tutorialベースです)。

# 前提:作業ディレクトリにいる
$ python3.8 -m venv myvenv
$ . myvenv/bin/activate

# ... 上で挙げたパッケージをpip installする

$ django-admin startproject mysite .

# ... Django Girls Tutorialに沿って「設定変更」する(mysite/settings.pyを変更)

$ python manage.py migrate

作業ディレクトリの状態

.
├── db.sqlite3
├── manage.py
├── mysite
└── myvenv

settings.py 変更(URL & テンプレート追加)

django-allauthを使うために、まず mysite/settings.py を変更。

INSTALLED_APPS = [
    # : すでにあるものの下に以下を追加
    'django.contrib.sites',  # django-allauthに必要

    'allauth',
    'allauth.account',
    'allauth.socialaccount',
    'allauth.socialaccount.providers.github',
]

# ... 途中を省略 ... 以下は一番下に追加

##################
# Authentication #
##################

SITE_ID = 1

LOGIN_REDIRECT_URL = "home"
ACCOUNT_LOGOUT_REDIRECT_URL = "account_login"

django-allauthをインストールしたので、migrateが必要です。

続いて、以下の2つのファイルを用意します。

mysite/urls.py3

urlpatterns = [
    path('admin/', admin.site.urls),
    # 以下2行を追加
    path('', TemplateView.as_view(template_name='home.html'), name='home'),
    path('accounts/', include('allauth.urls')),
]

templates/home.html4(新規作成)

<!DOCTYPE html>
<html lang="ja">
  <head>
    <meta charset="UTF-8">
    <meta name="viewport"
      content="width=device-width, initial-scale=1, shrink-to-fit=no">
    <title>ホーム</title>
  </head>
  <body>
    <h2>すごいアプリ</h2>
    {% if user.is_authenticated %}
      ようこそ {{ user.get_username }} さん
      <p><a href="{% url 'account_logout' %}">ログアウト</a></p>
    {% else %}
      <p><a href="{% url 'account_login' %}">ログイン</a></p>
    {% endif %}
  </body>
</html>

GitHub OAuth App作成

以下を参考にしました。

f:id:nikkie-ftnext:20201212204220p:plain

Authorization callback URLにはhttp://127.0.0.1:8000/accounts/github/login/callback/を設定。

Django Adminの操作

createsuperuserしてからDjango Adminにログインします。
「外部アカウント」の「Social applications」から追加していきます。

f:id:nikkie-ftnext:20201214131447p:plain

以上で、GitHubアカウントでログインできるようになります。

127.0.0.1:8000/(templates/home.htmlの表示)

f:id:nikkie-ftnext:20201212215812p:plain

「ログイン」をクリックするとログインページを表示(ビューとテンプレートはdjango-allauthが用意)
127.0.0.1:8000/accounts/login/

f:id:nikkie-ftnext:20201212215825p:plain

GitHubで初回ログイン(認可を求められる)※同じブラウザですでにGitHubにログインしています

f:id:nikkie-ftnext:20201212215837p:plain

ログイン状態で 127.0.0.1:8000/ に戻る

f:id:nikkie-ftnext:20201212215853p:plain

素振り2:Slackアカウントでもログイン

半年前にやりたかったSlackアカウントでのログインに挑戦してみます。

  1. Slack App作成
  2. Django Adminの操作の代わりにmysite/settings.pyに設定追加

Slack App作成

SlackはWorkspaceごとにアカウントがありますが、ログインに使いたいアカウントのあるWorkspaceでAppを作ります。

f:id:nikkie-ftnext:20201212220131p:plain

「OAuth & Permissions」に以下を設定しています

  • Redirect URLs
    • http://127.0.0.1:8000/accounts/slack/login/callback/5
  • Scopes > User Token Scopes
    • 未設定だとAppのインストールができないと表示されました
    • Slackのドキュメントによるとidentityが必要なようなので、identity.basicを設定

mysite/settings.pyに設定追加

Django Adminで操作しなくても、mysite/settings.pyに設定を追加してもできるようです。

INSTALLED_APPS = [
    # 省略。以下を追加
    'allauth.socialaccount.providers.slack',
]

# 省略

##################
# Authentication #
##################

# 省略。一番下に以下を追加
SOCIALACCOUNT_PROVIDERS = {
    # GitHub用のSocial applicationを削除して以下でも動きます
    # "github": {
    #     "APP": {
    #         "client_id": env("GITHUB_OAUTH_CLIENT_ID"),
    #         "secret": env("GITHUB_OAUTH_SECRET"),
    #     }
    # },
    "slack": {
        "APP": {
            "client_id": env("SLACK_OAUTH_CLIENT_ID"),
            "secret": env("SLACK_OAUTH_SECRET"),
        }
    },
}

127.0.0.1:8000/accounts/login/ にSlackアカウントでログインするためのリンクが追加されます!

f:id:nikkie-ftnext:20201212221020p:plain

リンクをクリックすると、Slackアカウントでのログインにあたり許可が求められます。

f:id:nikkie-ftnext:20201212221116p:plain

なお、今回はGitHubアカウントで連携してログインした後、http://127.0.0.1:8000/accounts/social/connections/ にアクセスしてSlackアカウントも連携しました。
なので、SlackアカウントでログインするとGitHubアカウントでログインしたときと同じように表示されます。

f:id:nikkie-ftnext:20201212215853p:plain

account_loginを経由せず、homeから直接ログインできるようにする

ここまでで作ったアプリは、homeからaccount_login(django-allauthが用意するログインページ)に遷移してログインします。

templates/home.html(新規作成)

      <p><a href="{% url 'account_login' %}">ログイン</a></p>

homeから直接ログインできるように、ソースコードを見ていじってみました(もっといいやり方をご存知の方いたら教えていただけると嬉しいです)。

      <!-- <p><a href="{% url 'account_login' %}">ログイン</a></p> -->
      お持ちの外部アカウントでログインをどうぞ
      <ul class="socialaccount_providers">
        {% include "socialaccount/snippets/provider_list.html" with process="login" %}
      </ul>

f:id:nikkie-ftnext:20201213195444p:plain

参考にしたのは、allauth/templates/account/login.html6
ソースコードを少し見たところ、settings.pyで有効にしたprovider(今回はGitHubとSlack)について、ログインに使うリンクが作られる挙動のようでした。

素振りしてみて

素振りする前は、キャッチアップが大変そうという印象のdjango-allauthでしたが、akiyokoさんの本を経由してドキュメントを読み、「ソースコード周りはsettings.pyの設定だけでソーシャルアカウント連携が実装できる!便利」と印象は大きく変わりました。
今回の素振りを元にやってみたい項目は以下です(年内にできたらいいな)。

  • レビュー用WebアプリでSlackアカウントでのログインを置き換える(力試し)
  • django-allauthリポジトリにあったexampleで素振りしてみる

django-allauthを使うと、ソーシャルアカウント連携は設定が大部分という感触を得ました。
来年作るDjangoアプリでは積極的に使っていけそうです!

補足:django-environ

先のコードで登場した env("SLACK_OAUTH_CLIENT_ID") などについて補足します。

OAuthの設定に必要なClient IDやSecret、DjangoSECRET_KEYなどは環境変数に設定していますが、コードではdjango-environで扱っています。
これも知ったのはakiyokoさんの本(実践編)です。

使い方は簡単で、ドキュメントの冒頭のコードが参考になります。

mysite/settings.py

import environ

env = environ.Env(DEBUG=(bool, False))
environ.Env.read_env(env_file=str(BASE_DIR / ".env"))

今回はリポジトリのルート(BASE_DIR)に.envファイルを置きました。
.envファイルを示すpathlib.Pathが受け取れないようなので、文字列に変換して渡しています。
環境変数.envファイルでまとめて管理でき、便利です。

.envファイルのイメージ

DEBUG=on
SECRET_KEY=very_very_secret_key

SLACK_OAUTH_CLIENT_ID=2****************4
SLACK_OAUTH_SECRET=hi_mi_tsu

  1. YouTubeアーカイブもあります。

  2. 嬉しいお言葉もいただきました。ありがとうございます。「いつ作ってるんあろうと思うぐらい作りこまれてまして」ref: まったりLog残し - PyCon JP 2020に参加してきました

  3. django.views.generic.TemplateViewはakiyokoさんの『基礎編』の教科書に解説があります

  4. リポジトリルートのtemplatesディレクトリからテンプレートを探せるように、mysite/settings.pyTEMPLATESDIRSBASE_DIR / "templates" を追加する必要があります

  5. ref: https://django-allauth.readthedocs.io/en/latest/providers.html#slack

  6. urls.pyを見たところ、account_loginという名前のパスに対応するビューはLoginViewでした。settings.pyで設定をしていない場合、account/login.htmlという名前のテンプレートが使われるようでした