見出し画像

【サンプルコード付き】Django ユーザー認証をオブジェクト指向で全構築する方法

1. 今回の記事の内容

こんにちは、ぎーたかです。

DjangoでWebサービスを作ろうとするとき、多くの場合ユーザー認証系の機能が必要になるかと思います。
その作成の中で、以下の様な悩みを抱える方は少なくないかと思います。

■ユーザー認証系機能作成の悩み
・必要な機能が多く、作成が大変
・機能を1から作ると意外に難しく、作成方法が分からない

こうした悩みも、書籍に掲載されているコードを参考にしたり、Djangoの標準機能を使ったりすれば解決する、と筆者は考えています。

実際、筆者自身は初めてのポートフォリオ作成にあたり、ユーザー機能の実装購入書籍のコードをかなり参考にして作成しました。そのため、特段悩むことはなく認証系の機能を作り上げられたと感じています。
が、Djangoの認証系の標準機能は非常に豊富で、そちらを活用すればもっと簡単に実装できると気づき、この認証系の標準機能を記事で紹介しようと考えました。

この記事を読むことで、Djangoの認証系の標準機能に含まれる機能の豊富さとともに、その実装の簡単さも理解することができます。
そのため、実際にユーザー認証系機能の作成で悩みを抱えていた方にとっては、機能開発のヒントや答えが見つかるかと思います。

読者の方の中には、「一度は自分で一通り作成してみないとダメじゃないの?」と感じる方もいるかと思います。しかし、他人が設計・実装したコードを自分のプログラムに取り込むことも、プログラマに最も重要な”車輪の再発明を避ける”思考法が養われます。
特に、Python等のオブジェクト指向型言語のコーディングでは重要な考え方になりますので、ぜひこの記事をきっかけに考え方を習得したり、積極的に挑戦してみる姿勢を持っていただけると嬉しいです。

それでは、まずは認証系の標準機能の一覧を解説していきましょう。

2. 紹介する認証系の標準機能

Djangoのユーザー認証系に関して、標準で備わっている機能を紹介します。
下の表にこの記事で紹介する機能をまとめました。

ただし標準機能を使う場合、デフォルトでは規定のURLパターンで各機能がルーティングされていることに注意してください。

ユーザー標準機能一覧

上記を見ていただければ、よくあるユーザー認証系の機能が一通り含まれていると、感じていただけるのではないでしょうか。

さて、Djangoの認証系の標準機能の破壊力はここからです。
次に実装がどれほど簡単か、手順の解説から体感してもらいましょう。

3. 標準機能の実装

前提にするフォルダ構成は、以下で設定/HTML用/静的ファイル用のディレクトリしかない(アプリディレクトリはない)と考えてください。

pjt
├── config                    #設定ディレクトリ
│   ├── __init__.py
│   ├── asgi.py
│   ├── settings.py
│   ├── urls.py
│   ├── views.py                
│   '── wsgi.py
├── static                    #静的ファイルディレクトリ
├── templates                 #htmlファイル用ディレクトリ
'── manage.py

①django-allauthのインストール
まずは、django-allauthのライブラリを環境にインストールします。
以下の1行分だけ実行すればOKです。

$pip install django-allauth

②settings.pyのINSTALLED_APPSに設定追記
利用する標準機能をINSTALLED _APPSに追記して、宣言します。
追加されるのは、以下の追記コードの4行です。

■config/settings.py

INSTALLED_APPS = [
   'django.contrib.admin',
   'django.contrib.auth',
   'django.contrib.contenttypes',
   'django.contrib.sessions',
   'django.contrib.messages',
   'django.contrib.staticfiles',
   'django.contrib.sites',         # 追加
   'allauth',                      # 追加
   'allauth.account',              # 追加
   'allauth.socialaccount',        # 追加
]

③urls.pyのルーティングを追加
accountsにくるURLリクエストを全てallauth.urlsに処理してもらいます。
追加されるのは、以下の追記分の2行です。

■config/urls.py

from django.contrib import admin
from django.urls import path, include             #include追記

urlpatterns = [
   path('admin/', admin.site.urls),
   path('accounts/', include('allauth.urls')),    #追記
]

④settings.pyで標準機能の細部のオプションを設定
今回は”よく見る”認証系の機能に寄せる様にした、オプションの設定例を紹介します。

■仮置きオプション
ユーザー登録/パスワード再設定の要求時に、指定メアドからメールを送付
ユーザー登録は、入力されたメアドに送るURLアクセス時に完了させる
ログイン認証は、"メールアドレス""パスワード"の照合で行う

上記のオプションで設定を記述すると、以下の通りです。改行とコメント分を省いて数えると15行ですね。

■config/settings.py

...(以下末尾に追記)
###### ↓認証系の設定 #####
AUTHENTICATION_BACKENDS = (
   'django.contrib.auth.backends.ModelBackend',            #おまじない
   'allauth.account.auth_backends.AuthenticationBackend',  #おまじない(ライブラリ使用のために追記)
)

ACCOUNT_AUTHENTICATION_METHOD = 'email'    #ログイン認証方法にemailを選定
ACCOUNT_USERNAME_REQUIRED = True           #USERNAMEをモデル上で入力任意に設定

ACCOUNT_EMAIL_VERIFICATION = 'mandatory'   #ユーザー登録時に、メール認証を実行する宣言(開発環境では'none'推奨)
ACCOUNT_EMAIL_REQUIRED = True              #EMAILをモデル上で入力必須に設定

SITE_ID = 1                                #おまじない。(django.contrib.sites利用時に必要な設定だが、意味は押さえなくていい。)

LOGIN_REDIRECT_URL = '/accounts/email'            #ログイン成功時のリダイレクトページ                        
ACCOUNT_LOGOUT_REDIRECT_URL = '/accounts/login/'  #ログアウト成功時のリダイレクトページ

###### メール送信アクションの設定 #####
EMAIL_BACKEND = "sendgrid_backend.SendgridBackend"      #おまじない(Email送信機能利用のために記述)
SENDGRID_API_KEY = 'SG.xxxxxxxx_xxxxxxxx_xxxxxxxx_xxxx' #SendGridのAPIキー(各自サービス登録と取得が必要)
SENDGRID_SANDBOX_MODE_IN_DEBUG = False                  #開発環境ではTrue推奨
DEFAULT_FROM_EMAIL = SERVER_EMAIL = '<xxxxx@gmail.com>' #メール送信元のアドレス宣言

別途、SendGrid(メール送信システム用のサービス)への登録と、APIキーの取得作業が必要ですが、実は実装作業はこれで全てです。

衝撃的ではないでしょうか?
これまでに記述した全22行で、冒頭に説明した標準機能群が全て対応するURLで確認・実行できる様になっています。残りの作業は、CSS/JSで見た目を整えていくことのみといっても過言ではありません。
実際、どのような機能が作成されているのか、次の章から解説していきましょう。

※補足
上記④標準機能の細部のオプション設定で、本記事では解説簡素化のため、APIキーをsettings.pyファイルに記述していますが、本来は原則禁止な運用です。
GitHubなどでバージョン管理される対象のファイルに、サービスのキー情報を直接書き込むのは、第3者の不正利用・悪用を招きかねません。個人/チーム開発のどちらでも、GitHub等を利用する方は絶対にやめてください!

参考までに、代替案を提示しておきます。
①.envファイルを作り、その中に環境変数として記述して呼び出す
②.envファイルは、.gitignoreファイルに登録し、Githubにあげない
筆者は、どのキー類もこの方法で管理しています。
詳しいやり方は、以下の参考記事を読んでみてください。

4.1 ユーザー登録の標準機能

サービスにユーザー登録を行う機能です。

↓のGif画像の様に、ユーザー名・メールアドレス・パスワード・再確認パスワードの入力フォームが表示され、情報を入力することでユーザー登録が完了します。

ユーザー登録

Gifの例では、settings.pyの認証機能オプション用の設定において、
・ACCOUNT_USERNAME_REQUIRED = True(ユーザー名の登録を必須)
・ACCOUNT_EMAIL_REQUIRED = True(Emailの登録を必須)
・ACCOUNT_EMAIL_VERIFICATION = 'none'(Email認証をなし)
・LOGIN_REDIRECT_URL = '/accounts/email'(処理後はメール設定画面へ)
とした場合の挙動をキャプチャしています。

なので、もし”ユーザー名の登録をしたくない”なら、USERNAMEの必須設定をFalseにすれば、新規登録の段階から入力を省かせることができます。
また、もし”Email認証できた場合のみユーザー登録を実行したい”なら、EMAIL_VERIFICATIONの設定を'mandatory'にしておけば、認証実施用のメールをフォームで入力されたメールアドレスに送付し、そのメール上のURLを踏んだ時にユーザー登録完了される設定にすることもできます。

その他、この標準機能のアピールポイントとして、無効なメールアドレス(ドメインなし)や、脆弱なパスワード(短すぎる or 単調すぎる)では登録されない様にエラーを出してくれる機能がついています。
もちろん再入力内容が1回目と異なる場合もエラーを出します。

たった22行の実装で、一般的に”よく見る”ユーザー登録機能をしっかり全部含んだ機能が手に入るなんて素晴らしすぎますね。
次は、ログイン/ログアウトの標準機能です。

4.2 ログイン/ログアウトの標準機能

■ログイン
サービスに登録したユーザー情報でログインする機能です。

↓のGif画像の様に、メールアドレス・パスワードの入力フォームが表示され、登録した情報を入力することでログインが完了します。

ログイン

Gifの例では、settings.pyの認証機能オプション用の設定において、
・ACCOUNT_AUTHENTICATION_METHOD = 'email'(Emailログイン認証)
・LOGIN_REDIRECT_URL = '/accounts/email'(処理後はメール設定画面へ)
とした場合の挙動をキャプチャしています。

なので、もし”ユーザーとパスワードでログインさせたい”なら、AUTHENTICATION_METHODを'username'にすれば、ユーザー名の認証でログインさせることができます。
また、もし”ログイン後に移動するページを変えたい”なら、LOGIN_REDIRECT_URLに別ページのURLを設定すれば、希望のURLに遷移させることもできます。

■ログアウト
ログイン中のユーザーアカウントを、ログアウトさせる機能です。

↓のGif画像の様に、ログアウトボタンが表示され、押下することでログアウトが完了します。

ログアウト

Gifの例では、settings.pyの認証機能オプション用の設定において、
・ACCOUNT_LOGOUT_REDIRECT_URL = '/accounts/login/'
(処理後はログイン画面へ)
とした場合の挙動をキャプチャしています。

もし”ログアウト後に移動するページを変えたい”なら、ACCOUNT _LOGOUT_REDIRECT_URLに別ページのURLを設定すれば、希望のURLに遷移させることもできます。

Djangoの認証系の標準機能、とんでもなさすぎます。
これだけの機能を、view.pyファイルやmodel.pyファイルは1行すら書かなくても実装できるなら、もはや1から認証機能を作ることに価値はないのかもしれませんね。

4.3 パスワード変更の標準機能

ログインユーザーが自分のパスワードを更新するための機能です。

↓のGif画像の様に、旧パスワード・新パスワード・再確認用の新パスワード入力フォームが表示され、入力することで登録パスワードの変更が完了します。

パスワード変更

こちらもユーザー登録のパスワード入力フォームと同様、パスワード入力フォームの検証機能が付与されています。

4.4 パスワード再設定の標準機能

パスワード入力画面で登録パスワードを思い出せなくなったユーザーが、パスワードリセットを実行するための機能です。

↓のGif画像の様に、パスワード再設定用のメール送信先のメールアドレス入力フォームが表示され、入力することでパスワードリセット用のURLのメール送信が完了します。

パスワード再設定

このGifは、ローカル開発環境での実行結果をキャプチャしています。

ローカルサーバーでの実行環境下でも、再設定メール送信先を入力後は、SendGridのAPI経由でちゃんとメールが届き、開封・URLクリックで再設定用のページが表示され、再設定のステップを進めることができます。

もちろんパスワード入力フォームには、検証機能がついています。

4.5 登録メールアドレスの編集の標準機能

登録したメールアドレスを、別のメールアドレスと差し替えられる機能です。

↓のGif画像の様に、登録メールアドレスの編集用画面が表示され、入力・クリック操作することでメールアドレス登録状況を編集できます。

登録メールアドレスの編集

今回の記事で取り上げる機能の紹介は以上ですが、いかがでしたか?
認証系だけでも、かなりの機能が必要で、かつ標準機能の実装の簡単さも伝わったかと思います。

最後に、皆さんの残る課題として”テンプレートデザインの編集”だけはご自身でやる必要があるので、その内容に軽く触れて本記事の解説を締めくくろうと思います。

4.6 テンプレートの編集方法

”自身のプロジェクトフォルダに全く何も作られていないのに、一体どうやって編集すればいいんだ”、と感じられる読者の方もいらっしゃるかと思います。

確かにその通りで、今回の標準機能で表示されたテンプレートファイルの編集には少し必要な手順があります。

■テンプレートの編集手順
①settings.pyにtemplatesフォルダにテンプレートを集約することを明記
②編集したいHTMLを配置すべき場所と、付けるべきファイル名を確認
③GitHubからソースファイルをダウンロードし、②の場所に配置
④以降、通常通り編集可能

標準機能は、デザインだけは編集の余白を残したものなので、便利ですが流石に編集しないと見栄えが悪いです。
ぜひ読者の皆さんそれぞれで、以下の参考記事と読みながら上記手順の①を、ソースファイルのリンクを読みながら②〜④の編集にトライしてみて欲しいです。

※補足
配置すべき場所の考え方は、戸惑う方もいるかもなのでログインファイルで例を提示しておくと、
プロジェクトディレクトリ直下>templates>account>にlogin.htmlという名前でGitのソースファイルをコピーすればOKです。

4.7 おまけ ~標準機能のカスタマイズ方法~

”あくまで標準機能をベースにしつつも、もう少し機能を変えたい”という方もいらっしゃるかと思います。

例えば、標準機能のパスワード入力フォームのバリデーション、これをデフォルトの条件から変えたいという時があるのではないでしょうか。この要望も、少し実装難易度は上がりますが可能です。

ソースコードの継承と、オーバーライドをする必要がありますが、標準機能で決められたURL・View(・Form)の関係性を理解しながら1つずつ実施すれば、なんとか実装可能なレベルかと思います。

例えば、新規登録画面で入力させるフィールドを増やしたい場合は、
①$django-admin startapp accountsでaccountsのアプリを追加
②config/urls.pyに"accounts/"をaccounts.urlに紐付ける設定を追記
③accounts/urls.pyに変更を加えたい機能のルーティングを追加
④③に紐づけるviewをデフォルトのallauth.viewのビューから継承し機能変更
⑤必要に応じて④に紐づけるformをデフォルトのallauth.formから継承・変更
という上記の手順で実装を進めれば機能の変更が可能になります。

以下、一応程度で参考記事を貼っておきますが、継承のイメージが湧かない方の理解をサポートするくらいの効果しかないかと思います。
この記事と、ソースコードのviews.py、forms.pyを参考にしながら、機能追加にもチャレンジしてみると、オブジェクト指向な開発の実力が身につくかと思うので、ぜひ頑張ってみて欲しいです。
もしご要望があれば、機能追加の解説も検討しますので、よろしければコメントいただけると嬉しいです。

5. まとめ

今回の記事、いかがでしたか?

筆者は自身のポートフォリオ作成の過程で、認証機能は書籍を参考にしながら自作しました。その後、この記事で取り上げた標準機能に出会いましたが、”もっと早く知っていればよかった”というのが本音です。

認証機能の様な”作れて当たり前”の機能に時間を取られるよりも、ポートフォリオの肝となり、オリジナリティを表現できる機能の作り込みに注力すべきだと筆者は考えます。

標準機能はまさに上記の要望に応える打って付けの便利機能なので、ぜひ読者の皆さんも使いこなして、より楽しいWeb開発ライフを送っていただけると嬉しいです!

これからもDjangoの学習者・開発者に向けた、開発のサポートになる記事を作っていくので、もしよろしければこれからも読んでいっていただけると嬉しいです。

よろしければサポートをお願いします🙇‍♂️ いただいたサポートは、クリエイターの活動資金として使わせていただきます😌 活動を通してえた経験を、また記事として皆さんと共有します👍