Djangoなソーシャルログイン

Python,TIPSDjango

近年ではSNSを使用したサインアップ・ログインを利用できるWEBサービスが増えています。
Djangoでも外部ライブラリを使用することでSocial Authを簡単に実現することができます。
今回は social-auth-app-django というライブラリを使用してGoogle, Facebook, Twitter, GitHubのアカウントを使用して認証を行う方法を紹介します。

標準のサインアップ機能の実装パターンについてはこちらを参照して下さい。

事前準備

まずはライブラリをインストールします。

pip install social-auth-app-django

次にsettings.appに追記をします。

settings.py

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',

    'social_django',  # これを追加する

]

最後にマイグレーションします。

$ python manage.py migrate

Operations to perform:
  Apply all migrations: admin, auth, contenttypes, sessions, social_django
Running migrations:
  Applying social_django.0001_initial... OK
  Applying social_django.0002_add_related_name... OK
  Applying social_django.0003_alter_email_max_length... OK
  Applying social_django.0004_auto_20160423_0400... OK
  Applying social_django.0005_auto_20160727_2333... OK
  Applying social_django.0006_partial... OK

これでインストールが完了しました。
social-auth-app-djangoはOAuthとOAuth2を使用するのに必要な情報を全て保持しています。
基本的に我々はそれを手動で処理する必要もユーザーのSNSプロフィールにアクセスする必要もありません。

全般設定

それではもう少し動作させるための設定をしていきます。
まずはMIDDLEWARE_CLASSESに以下追記をします。

settings.py

MIDDLEWARE_CLASSES = [
    'django.middleware.security.SecurityMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.common.CommonMiddleware',
    'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.auth.middleware.SessionAuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    'django.middleware.clickjacking.XFrameOptionsMiddleware',

    'social_django.middleware.SocialAuthExceptionMiddleware',  # これを追加
]

次にTEMPLATESに以下追記をします。

TEMPLATES = [
    {
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        'DIRS': [
            PROJECT_DIR.child('templates'),
        ],
        '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', # これを追加
            ]
        },
    },
]

そしてAUTHENTICATION_BACKENDSを定義します。

AUTHENTICATION_BACKENDS = (
    'social_core.backends.open_id.OpenIdAuth',
    'social_core.backends.google.GoogleOpenId',
    'social_core.backends.google.GoogleOAuth2',

    'social_core.backends.github.GithubOAuth2',
    'social_core.backends.twitter.TwitterOAuth',
    'social_core.backends.facebook.FacebookOAuth2',

    'django.contrib.auth.backends.ModelBackend',
)

上の3つは全てGoogle用になります。
後は見ての通りGitHub, Twitter, Facebook用のバックエンドです。
最後の行に記載している 'django.contrib.auth.backends.ModelBackend', は必ず入れて下さい。
これを消してしまうとユーザーはDjango認証Modelを介してログインできなくなってしまいます。

それでは次は認証用のURLを定義します。

urls.py

from django.contrib import admin
from django.conf.urls import include
from django.urls import path
from django.contrib.auth import views as auth_views
from . import views

urlpatterns = [
    path('admin/', admin.site.urls),
    path('', views.index, name='index'),
    path('login/', auth_views.LoginView.as_view(), name='login'),
    path('logout/', auth_views.LogoutView.as_view(), name='logout'),
    path('oauth/', include('social_django.urls', namespace='social')),
    path('accounts/profile/', views.index, name='index')
]

LOGIN_URLとLOGIN_REDIRECT_URLを設定します。
LOGIN_REDIRECT_URLは認証後にユーザーをリダイレクトするために使用されます。

settings.py

LOGIN_URL = 'login'
LOGIN_REDIRECT_URL = 'home'

さあこれで全ての準備が整いました。
ここからはSNS毎にアプリへ登録する必要があり、その手順はそれぞれ異なっています。
まずはGoogle認証から説明します。

Google認証

まずは クライアントキークライアントシークレット を取得しましょう。
Goolge Developers Console へアクセスして下さい。

※ もし既に適当なプロジェクトを保有している場合は項番4までスキップして下さい。

1.) 画面左上にある [プロジェクトの選択] を押下します。
2.) 続いてダイアログ右上の [新しいプロジェクト] を押下します。

3.) プロジェクト名に適当な名称を入力し [作成] を押下します。
4.) 画面左側の [認証情報] を押下します。
5.) 画面上部の [OAuth 同意画面] を押下します。
6.) アプリケーション名に適当な名称を入力します。
7.) 他の部分は全て空欄のまま [保存] を押下します。
8.) [認証情報] タブを押下します。
9.) 画面下部の [認証情報を作成] を押下し、 OAuthクライアントID を選択します。

10.) ウェブアプリケーション を選択します。
11.) 名前に適当な名称を入力します。
12.) [承認済みのリダイレクト URI] 部に以下URLを入力します。
http://127.0.0.1:8000/oauth/complete/google-oauth2/
http://localhost:8000/oauth/complete/google-oauth2/

13.) [作成] を押下します。

上記手順でモーダル表示される クライアントIDクライアント シークレットをsettings.pyへ追記します。

settings.py

SOCIAL_AUTH_GOOGLE_OAUTH2_KEY = 'hogehoge'  # クライアントID
SOCIAL_AUTH_GOOGLE_OAUTH2_SECRET = 'hogehoge' # クライアント シークレット

設定はこれで完了です。
次に処理を実装していきます。

views.py

from django.shortcuts import render


def index(request):
    return render(request, 'index.html')

index.html

{% extends 'base.html' %}

{% block content %}
    {% if user.is_authenticated %}
        <h1>{{ user.username }}さんがログイン中です</h1>
        <a href="{% url 'logout' %}">ログアウト</a>
    {% else %}
        <h1>メインメニュー</h1>
        <p>メニューと言いつつログインする他選択肢は無い</p>
        <a href="{% url 'login' %}">ログインする</a>

    {% endif %}

{% endblock content %}


次にログイン画面とログアウト画面を用意します。

login.html

{% extends 'base.html' %}

{% block content %}

  <h2>ソーシャルサービスを選択してログイン</h2>
  <ul>
    <li><a href="{% url 'social:begin' 'google-oauth2' %}">Googleでログイン</a></li>
  </ul>

  <a href="{% url 'index' %}">戻る</a>
{% endblock content %}

logged_out.html

{% extends 'base.html' %}

{% block title %}Logout{% endblock %}

{% block content %}
<h1>Log Out</h1>
<p>
ログアウトしました。<br>
再度ログインする場合は<a href="{% url 'index' %}">コチラ</a>から実施してください。
</p>

{% endblock %}

以上で実装は完了です。

認証に成功するとGoogleアカウントのIDが取得されレンダリングされます。

Facebook認証

Facebookでの認証にはSDKの導入が必要となります。
SDKを使わないトークン生成も可能ですがこちらは有効期限が存在します。
今回はSDKを使わずに実装していきます。

まずfacebook for developersにログインします。
※ developersアカウントが必要です、無料でサインアップできます。

ログイン後、画面上部にある [マイアプリ] を押下します。
[アプリ作成] を押下します。

モーダルウィンドウで[表示名]に適当な名称を入力し、[アプリIDを作成してください] を押下します。
シナリオの選択 画面に推移したら下にスクロールし [スキップ] を押下します。

画面左のメニューから [設定] – [ベーシック] と進み、アプリIDapp secret を表示させます。
表示させたら設定に追記しましょう。

settings.py

SOCIAL_AUTH_FACEBOOK_KEY = 'hogehoge'  # アプリID
SOCIAL_AUTH_FACEBOOK_SECRET = 'hogehoge'  # app secret

NOTE: 基本的にこの手のシークレットキーなどの情報をsettings.pyにハードコーディングすることはオススメしません。
本番環境ではでカップリングしておくことをオススメします。
今回はテスト環境での実行という大義名分があるので直接書き込んでいます。

次にFacebook for developers 側にDjangoの設定をしていきます。
先程の[設定] – [ベーシック] へと戻ります。

[アプリドメイン] の欄にlocalhost と入力します。
画面最下部へスクロールし、[+ プラットフォームを追加] – [WEBサイト] をクリックし、[サイトURL] 欄に http://localhost:8000/ と入力し [変更を保存] を押下します。

早速Facebookアカウントを使用してログインしてみます。
まずはログイン用のリンクを追加します。

login.html

{% extends 'base.html' %}

{% block content %}

  <h2>ソーシャルサービスを選択してログイン</h2>
  <ul>
    <li><a href="{% url 'social:begin' 'google-oauth2' %}">Googleでログイン</a></li>
  </ul>
  <ul>
    <li><a href="{% url 'social:begin' 'facebook' %}">Facebookでログイン</a></li>
  </ul>

  <a href="{% url 'index' %}">戻る</a>
{% endblock content %}


Facebookでのログインは最近からhttps化が必須になっており、通常のlocalhostではhttpとなってしまうのでログイン検証をすることができません。
手っ取り早くテストするために一旦以下コマンドでDjangoの開発サーバを立ち上げ直します。

HTTPS=on python manage.py runserver 0.0.0.0:8003

HTTPS=on をつけることで実際にはhttps化していなくてもrequest.is_secure()などにTrueを返す様になります。
それでは改めてFacebookログインを試してみます。

うまくいきましたね。
もしも、

このサイトは安全に接続できません localhost から無効な応答が送信されました。 ERR_SSL_PROTOCOL_ERROR

というエラーが返った場合はアドレスバーにhttps:// が含まれていることが原因ですので取り除いてやると正常にレンダリングされます。

Twitter認証

パブリックなWEBアプリを作成する際にはTwitterでの認証が最も使用頻度が高いのでは無いでしょうか。
Twitter認証を行うには

  • Counsumer Key
  • Consumer Secret

の2点が必要です。
まずはDeveloperサイトへログインしましょう。

[Create an app] を押下します。
必須項目とCallback URLを埋めて作成までいきます。
この時Callback URLは適当な値ではなく実際に返すURLを入力して下さい、誤った指定をするとHTTPErrorが帰ります。

作成されたアプリのKeys and Access Tokensタブに移動しKeyとSecretを取得しsettings.pyへ追記します。

settings.py

SOCIAL_AUTH_TWITTER_KEY = 'hogehoge' # Consumer Key
SOCIAL_AUTH_TWITTER_SECRET = 'hogehoge' # Consumer Secret

テンプレートへTwitter認証用のURLを定義します。

urls.py

{% extends 'base.html' %}

{% block content %}

  <h2>ソーシャルサービスを選択してログイン</h2>
  <ul>
    <li><a href="{% url 'social:begin' 'google-oauth2' %}">Googleでログイン</a></li>
  </ul>
  <ul>
    <li><a href="{% url 'social:begin' 'facebook' %}">Facebookでログイン</a></li>
  </ul>
  <ul>
    <li><a href="{% url 'social:begin' 'twitter' %}">Twitterでログイン</a></li>
  </ul>

  <a href="{% url 'index' %}">戻る</a>
{% endblock content %}

GitHub認証

まずはGitHubアカウントにログインしSettingを開きます。
左側のメニューに表示されている [Developer settings] – [OAuth Apps] と進みます。

新規作成を押下し、各項目を入力し [Register application] を押下します。

0usersの部分に記載されている、Client ID, Client Secret を設定に追記します。

settings.py

SOCIAL_AUTH_GITHUB_KEY = 'hogehoge' # Client ID
SOCIAL_AUTH_GITHUB_SECRET = 'hogehoge' # Client Secret

これだけで完了です、4種の中では一番実装が簡単だと思います。
実際にログインを試してみるとこの様に推移します。


まとめ

以上でGoogle, Facebook, Twitter, GitHubでのソーシャルログイン実装方法の説明を終わります。
クローズ・パブリック共にソーシャルログインに対応したサービスは多くリリースされています。

前回の記事で説明したDjango単独でのサインアップと併用し、ユーザーにサインアップの選択肢を増やすことをオススメします。
ソーシャルログインのいいところはログインとサインアップのプロセスがほぼ同じである点です。

今回は開発環境での実装を目的にしたので settings.py へ各サービスのKey情報を埋め込みましたが、本番環境では避けるべきです。
今度本番環境用の設定情報のカップリングについても投稿しようと思います。


この投稿で作成したコードはGitHubへアップしてあります。
https://github.com/mila411/django-social-auth

Python,TIPSDjango

Posted by Kenny