【django】ログイン認証機能:パスワードリセット機能を組み込む方法

時計 2021.04.09 / 時計

【django】ログイン認証機能:パスワードリセット機能を組み込む方法

本記事では、PythonのWebフレームワークdjangoを使ったログイン認証機能における、アカウントのパスワードリセットする機能を組み込む方法について解説していきます。

djangoにはWebアプリケーションで必須となるログイン認証機能が最初から備わっています。一から作成するには時間がかかるパスワードリセット機能もdjangoには用意されています。

パスワードのリセット機能はWebアプリケーションに組み込むのは非常に簡単ですが、仕組みを理解するのが少し難しいです。

初めてパスワードリセット機能を使う方にもわかるように、詳しく説明していきたいと思います。

本記事を通して以下の知識を学べます。

学べる知識
  • ログイン認証機能を提供しているdjango.contrib.authについて
  • パスワードリセットで使用する4つのビューの使い方
  • メールの送信設定について

Djangoに組み込まれているパスワードリセット機能

冒頭でも説明していますが、djangoにはインストールしたらすぐに使えるログイン認証機能が用意されています。

ここではログイン認証に使われるパスワードをリセットする機能について解説していきます。

パスワードリセット機能とは

初めてログイン認証機能を含んだWebアプリケーションを作成する人には、パスワードリセット機能がそもそも何かわからないかもしれないです。

パスワードリセットとは、パスワードを忘れた場合に、パスワードを再設定できるようにした機能のことです。

パスワードリセットの流れ

パスワードリセットでは、Webアプリケーションのみで行えるわけでなくメールも使用します。

ユーザーの登録しているメールアドレス宛にパスワードリセットページのURLが送られます。
そのURLからパスワード更新ページへ移動し、新しいパスワードを入力します。

まとめるとユーザーは以下の流れでパスワードをリセットできます。

  1. パスワードリセットページでメールアドレスを入力
  2. メール送信完了ページが表示され、パスワードリセットメールを受信
  3. メールに記載されているリンクをクリック
  4. パスワード更新ページから新パスワードを設定
  5. パスワード更新完了ページが表示

上記のパスワードリセットの流れを理解していただくと、プログラムを組むのがスムーズに進みます。

次にパスワードリセットで使用するビューについて解説します。

django.contrib.auth

ログインやログアウト、パスワード変更、パスワードリセットなどのログイン認証機能は、django.contrib.authアプリケーションが提供しています。

仮想環境venvでは、以下のようなパスに保存されています。

venv\Lib\site-packages\django\contrib\auth\

ログイン認証機能は、authアプリケーション内のviews.pyに使用するビューが記載されています。

django.contrib.auth.views

django.contrib.auth内のviews.pyに記載されているクラスビューを使用して、ログイン認証機能が簡単に実現できます。

djangoに備わっているパスワードリセットでは、以下4つのビューを使用します。

  • PasswordResetView
  • PasswordResetDoneView
  • PasswordResetConfirmView
  • PasswordResetCompleteView

これらビューを使用するために、必ずプログラムの先頭でdjango.contrib.authからviewsをインポートするようにしてください。

from django.contrib.auth import views as auth_views

パスワードリセットで使用する4つのビューについて以下で解説します。

PasswordResetView

PasswordResetViewは、パスワードリセットのメールを送信するビューです。
テンプレートで使用する、パスワード入力用Form(PasswordResetForm)が用意されています。

メールに送られる本文も用意されていますので、文面を用意する必要もありません。

class PasswordResetView(PasswordContextMixin, FormView):
    email_template_name = 'registration/password_reset_email.html'
    extra_email_context = None
    form_class = PasswordResetForm
    from_email = None
    html_email_template_name = None
    subject_template_name = 'registration/password_reset_subject.txt'
    success_url = reverse_lazy('password_reset_done')
    template_name = 'registration/password_reset_form.html'
    title = _('Password reset')
    token_generator = default_token_generator

from_emailがデフォルトではNoneになっているため、実際に使用する際にはfrom_emailにメールアドレスを入れる必要はあります。

また入力されたメールアドレスのユーザーがアクティブ(is_activeがTrue)の場合のみにメールは送信されます。

メール送信が完了すると、URLconfの名前がpassword_reset_doneにページ遷移します。

PasswordResetDoneView

PasswordResetDoneViewは、メール送信後に表示されるページを表示するビューです。

class PasswordResetDoneView(PasswordContextMixin, TemplateView):
    template_name = 'registration/password_reset_done.html'
    title = _('Password reset sent')

PasswordResetConfirmView

PasswordResetConfirmViewは、受信したメールのURLをクリックすると表示されるパスワード更新ページを表示します。

表示されるページに新しく設定したいパスワードを入力します。

class PasswordResetConfirmView(PasswordContextMixin, FormView):
    form_class = SetPasswordForm
    post_reset_login = False
    post_reset_login_backend = None
    reset_url_token = 'set-password'
    success_url = reverse_lazy('password_reset_complete')
    template_name = 'registration/password_reset_confirm.html'
    title = _('Enter new password')
    token_generator = default_token_generator

post_reset_loginをTrueにすると、新しいパスワードを設定した後に、そのままログイン処理が行われます。デフォルト値はFalseです。

パスワード設定がが完了すると、URLconfの名前がpassword_reset_completeにページ遷移します。

PasswordResetCompleteView

PasswordResetCompleteViewは、パスワードのリセット処理が完了すると表示される、リセット完了ページを表示します。

class PasswordResetCompleteView(PasswordContextMixin, TemplateView):
    template_name = 'registration/password_reset_complete.html'
    title = _('Password reset complete')

メール送信設定

Webアプリケーションからパスワードリセットのためのメールを送信する必要があります。

そのためsettings.pyにメール送信サーバー情報を追加する必要があります。
以下にgmailの場合での設定例を記載します。

#Mail Setting
EMAIL_HOST = 'smtp.gmail.com'
EMAIL_PORT = 587
EMAIL_HOST_USER = 'gmailアカウント名'
EMAIL_HOST_PASSWORD = 'パスワード'
EMAIL_USE_TLS = True

詳しくは以下記事をご参照ください。

パスワードリセット機能を追加してみよう

では実際にWebアプリケーションにパスワードリセット機能を追加しましょう。
以下記事で作成したWebアプリケーションに対してパスワードリセット機能を追加します。

次の流れでパスワードリセット機能を追加していきます。

  1. urls.pyにルーティングを追加
  2. テンプレートの追加(4ページ)
  3. settings.pyにメール送信サーバー情報を追加
  4. login.htmlにパスワードリセットページへのリンクを追加

画面遷移

パスワードリセット機能を追加して完成する、Webアプリケーションの画面遷移を以下に記します。

  1. ログインページ
  2. djangoによるwebアプリケーション:ログイン画面
  3. パスワードリセットページ
  4. djangoによるwebアプリケーション:パスワードリセットページ
  5. メール送信完了ページ
  6. djangoによるwebアプリケーション:メール送信完了ページ
  7. パスワード更新ページ
  8. djangoによるwebアプリケーション:パスワード更新ページ
  9. パスワード更新完了ページ
  10. djangoによるwebアプリケーション:パスワード更新完了ページ

送信されるパスワード更新ページのリンクを含むメールは、デフォルトだと次のような内容です。

You're receiving this email because you requested a password reset for your user account at 127.0.0.1:8000.
Please go to the following page and choose a new password:

link

Your username, in case you’ve forgotten: root
Thanks for using our site!
The 127.0.0.1:8000 team

urls.pyにルーティングを追加

まずはプロジェクトのurls.pyに以下4つのURLルーティングを追加します。

path('accounts/password_reset_form/', auth_views.PasswordResetView.as_view(template_name='registration/password_reset.html', from_email=' office54@office54.net '), name='password_reset'),
path('accounts/password_reset_done/', auth_views.PasswordResetDoneView.as_view(template_name='registration/password_reset_mail_done.html'), name='password_reset_done'),
path('accounts/password_reset/<uidb64>/<token>/', auth_views.PasswordResetConfirmView.as_view(template_name='registration/password_reset_confirmation.html'), name='password_reset_confirm'),
path('accounts/password_reset_finish/', auth_views.PasswordResetCompleteView.as_view(template_name='registration/password_reset_finish.html'), name='password_reset_complete'),

パスワードリセットで使用する4つのビューへのルーティングを追加しました。

各ルーティングではオプションtemplate_nameを使って、クラスで使用するテンプレートを指定しています。

すでに備わっているクラスを使用しているので、views.pyへの記入は一切必要ありません。

テンプレートの追加

パスワードリセットで表示される4つのテンプレートを作成します。

password_reset_confirmation.html

{% extends "five/base.html" %}
{% block content %}
<h2>Password Reset Form</h2>
<form method="post" style="padding-left:20px;">
{% csrf_token %}
{{ form.as_p }}
<button type="submit">Reset Password</button>
</form>
{% endblock %}

password_reset_mail_done.html

{% extends "five/base.html" %}
{% block content %}
<h2>Your password reset Email has been sent.</h2>
{% endblock %}

password_reset.html

{% extends "five/base.html" %}
{% block content %}
<h2>Password Reset Form</h2>
<form method="post" style="padding-left:20px;">
{% csrf_token %}
{{ form.as_p }}
<button type="submit">Reset Password</button>
</form>
{% endblock %}

password_reset_finish.html

{% extends "five/base.html" %}
{% block content %}
<h2>Password reset complete</h2>
<p>Your password has been set. You may go ahead and log in now.</p>
<p><a href="{% url 'login' %}">Login</a></p>
{% endblock %}

settings.pyにメール設定を追加

settings.pyにメール送信サーバー情報を追加してください。

EMAIL_HOST = 'smtp.gmail.com'
EMAIL_PORT = 587
EMAIL_HOST_USER = 'office54@office54.net'
EMAIL_HOST_PASSWORD = '54545454'
EMAIL_USE_TLS = True

ソースコード

その他のページで変更した点を以下に記します。

コピペして実際に動く様子を確認してください。

login.html

{% extends "five/base.html" %}
{% block content %}
<h2>Login</h2>
<form method="post">
{% csrf_token %}
{{ form.as_p }}
<button type="submit">Login</button>
</form>
<p><a href="{% url 'password_reset' %}">Forgot Your Password?</a></p>    # 追加
{% endblock %}

urls.py:プロジェクト

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

urlpatterns = [
    path('admin/', admin.site.urls),
    path('', include('five.urls')),
    path('accounts/', include('django.contrib.auth.urls')),
    path('accounts/password_change_form/', auth_views.PasswordChangeView.as_view(template_name='registration/password_change.html'), name='password_change_form'),
    path('accounts/password_change_done/', auth_views.PasswordChangeDoneView.as_view(template_name='registration/password_change_finish.html'), name='password_change_done'),
    path('accounts/password_reset_form/', auth_views.PasswordResetView.as_view(template_name='registration/password_reset.html', from_email='admin-scan@system.benline.co.jp'), name='password_reset'),    # 追加
    path('accounts/password_reset_done/', auth_views.PasswordResetDoneView.as_view(template_name='registration/password_reset_mail_done.html'), name='password_reset_done'),    # 追加
    path('accounts/password_reset/<uidb64>/<token>/', auth_views.PasswordResetConfirmView.as_view(template_name='registration/password_reset_confirmation.html'), name='password_reset_confirm'),    # 追加
    path('accounts/password_reset_finish/', auth_views.PasswordResetCompleteView.as_view(template_name='registration/password_reset_finish.html'), name='password_reset_complete'),    # 追加
]

まとめ

本記事「【django】ログイン認証機能:パスワードリセット機能を組み込む方法」はいかがでしたか。

djangoに備わっている機能を使うことで、実装するのが難しいリセット機能が簡単にできました。

このように一から作ると時間がかかる機能も簡単に実装できるのが、フレームワークの良さの一つですよね。

ぜひみなさんもご自身のWebアプリケーションにパスワードリセット機能を組み込んでみてください。