Djangoにはデフォルトでユーザ認証機能の仕組みが実装されています。
いくつかのルールに従えば、以下のように簡単にログイン機能が実装できたので、その手順を備忘録としてまとめたいと思います。
なお、私の環境は以下です。
- Python: 3.8 (2020/3/22 時点の最新)
- Django: 3.0.4 (2020/3/22 時点の最新)
目的
Djangoのユーザ認証機能について
冒頭でも記載した通り、Djangoにはデフォルトでユーザ認証機能が搭載されており、それを利用することで以下のようなユーザ認証関連の機能を簡単に実装することができます。
- ログイン/ログアウト
- パスワード変更
- メールでのパスワード再設定
ただし、ここで注意なのが、デフォルトの機能として、ユーザ登録やユーザ情報変更は提供されておらず、自分で実装する必要があります。
以下では、ユーザ登録はDjangoの管理画面で登録する方針として、Djangoのデフォルトで利用できる機能のみを実装する方法をまとめます。
Djangoのユーザ認証機能の実装
Djangoのデフォルトで利用できる以下の機能について実装します。
- ログイン/ログアウト
- パスワード変更
- メールでのパスワード再設定
なお、ディレクトリ構成は以下のような構成となっています。
mysite
│ db.sqlite3
│ manage.py
│
├─config
│ │ urls.py
│ │ wsgi.py
│ │ __init__.py
│ │
│ └─settings
│ base.py
│ local.py
│ production.py
│ staging.py
│ test.py
│ __init__.py
│
├─static
│ ├─admin
│ │ └─***省略
| |
│ └─mystatic
│ └─css
│ style.css
│
└─templates
├─common
│ base.html
│
└─registration
logged_out.html
login.html
password_change_done.html
password_change_form.html
password_reset_complete.html
password_reset_confirm.html
password_reset_done.html
password_reset_email.html
password_reset_form.html
password_reset_subject.txt
URLパスの設定
Djangoの認証機能は、「django.contrib.auth
」で提供されているため、urls.py
に以下を追加します。
【config/urls.py】
from django.contrib import admin
from django.urls import include, path
urlpatterns = [
path('', include('home.urls')),
path('accounts/', include('django.contrib.auth.urls')),# これを追加
path('admin/', admin.site.urls),
]
home.urls
はホーム画面を表示するアプリです。詳細は割愛しますが、ログイン成功したらリダイレクトされるように設定します。
なお、「django.contrib.auth.urls
」のパスは以下のように規定されており、それぞれに対応しているテンプレートは決まっています。その通りの名称にしないとうまく動きません。
機能 | URLパス | テンプレート名 |
---|---|---|
ログイン | /accounts/login/ | login.html |
ログアウト | /accounts/logout/ | logged_out.html |
パスワード変更 | /accounts/password_change/ | password_change_form.html |
パスワード変更完了 | /accounts/password_change/done/ | password_change_done.html |
パスワード再設定メール送信 | /accounts/password_reset/ | password_reset_form.html |
パスワード再設定メール送信完了 | /accounts/password_reset/done/ | password_reset_done.html |
パスワード再設定 | /accounts/reset/<uidb64>/<token>/ | password_reset_confirm.html |
パスワード再設定完了 | /accounts/reset/done/ | password_reset_complete.html |
※パスワード変更はログイン可能なユーザがパスワードを変更する機能。パスワード再設定はパスワードが分からないユーザがパスワードを再設定する機能。パスワード再設定はメールアドレスでユーザを判定するため、事前のユーザ登録でメールアドレスを設定する必要がある。
ベースのテンプレートを作成
上の表でまとめた各機能を実装するうえで、各テンプレートを作成する必要があるのですが、ヘッダーなどの共通部分はベースのテンプレートにまとめることにします。
【templates/common/base.html】
<!DOCTYPE html>
{% load static %}
<html lang='ja'>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>HHBook</title>
<!-- css -->
<link href="{% static 'mystatic/css/style.css' %}" rel="stylesheet">
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/css/bootstrap.min.css"
integrity="sha384-Vkoo8x4CGsO3+Hhxv8T/Q5PaXtkKtu6ug5TOeNV6gBiFeWPGFN9MuhOf23Q9Ifjh" crossorigin="anonymous">
<!-- js -->
<script src="https://code.jquery.com/jquery-3.4.1.slim.min.js"
integrity="sha384-J6qa4849blE2+poT4WnyKhv5vZF5SrPo0iEjwBvKU7imGFAV0wwj1yYfoRSJoZ+n"
crossorigin="anonymous"></script>
<script src="https://cdn.jsdelivr.net/npm/popper.js@1.16.0/dist/umd/popper.min.js"
integrity="sha384-Q6E9RHvbIyZFJoft+2mJbHaEWldlvI9IOYy5n3zV9zzTtmI3UksdQRVvoxMfooAo"
crossorigin="anonymous"></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/js/bootstrap.min.js"
integrity="sha384-wfSDF2E50Y2D1uUdj0O3uMBJnjuUD4Ih7YwaYd1iqfktj0Uod8GCExl3Og8ifwB6"
crossorigin="anonymous"></script>
</head>
<body>
<div class="container">
<header>
<div class="title">{% block titele %}Sample{% endblock %}</div>
{% if user.is_authenticated %}
<p>{{ user.username }}でログイン中</p>
{% else %}
<p>ログインしていません</p>
{% endif %}
</header>
<!-- メインコンテンツ -->
<div class="content">
<!-- コンテンツ -->
{% block content %}{% endblock %}
</div>
</div>
</body>
</html>
- デザインにBootstrap4を使うために、CSSやJavascriptを設定しています。
- デザインについては、基本はBootstrap4を使っていますが、タイトルなどの一部デザインは「static/mystatic/css/style.css」で個人好みのものに設定しています。設定方法の詳細は「Djangoのユーザ認証機能のデザインを見直す」を参考にしてください。
ログイン/ログアウト機能実装
ログイン/ログアウト機能のために、以下ファイルを作成します。
- templates/registration/login.html
- ログイン用のテンプレート
- templates/registration/logged_out.html
- ログアウト用のテンプレート
ログイン用のテンプレート
【templates/registration/login.html】
{% extends "common/base.html" %}
{% block titele %}ログイン{% endblock %}
{% block content %}
<div>
<form method="post">
{% csrf_token %}
{{ form.as_p }}
<p><a href="{% url 'password_reset' %}">パスワードを忘れた</a></p>
<button type="submit" class="btn btn-primary">ログイン</button>
</form>
</div>
{% endblock %}
- 「
django.contrib.auth.form
」でフォームが規定されているので、form.as_p
を使って簡単にHTMLのフォームを生成しています。 - 「パスワードを忘れた」のリンクは後で作成するパスワード再設定機能に紐づけています。
- ログインボタンのデザインはBootstrap4を使っています。
なお、このログイン用のテンプレートを表示させると以下のようになります。
ログアウト用のテンプレート
【templates/registration/logged_out.html】
{% extends 'common/base.html' %}
{% block titele %}ログアウト{% endblock %}
{% block content %}
<h2>Logged Out</h2>
<p>ログアウトしました。</p>
<p><a href="{% url 'login' %}">再ログインする</a></p>
{% endblock %}
- 「再ログインする」には、ログイン画面へのリンクを紐づけています。
なお、このログアウト用のテンプレートを表示させると以下のようになります。
パスワード変更
パスワード変更機能のために、以下ファイルを作成します。
- templates/registration/password_change_form.html
- パスワード変更用のテンプレート
- templates/registration/password_change_done.html
- パスワード変更完了用のテンプレート
パスワード変更用のテンプレート
【templates/registration/password_change_form.html】
{% extends "common/base.html" %}
{% load static %}
{% block titele %}パスワード変更{% endblock %}
{% block content %}
<div>
<form method="post">
{% csrf_token %}
{{ form.as_p }}
<button type="submit" class="btn btn-primary">パスワード変更</button>
</form>
</div>
{% endblock %}
- 「
django.contrib.auth.form
」でフォームが規定されているので、form.as_p
を使って簡単にHTMLのフォームを生成しています。 - パスワード変更ボタンのデザインはBootstrap4を使っています。
なお、このパスワード変更用のテンプレートを表示させると以下のようになります。
パスワード変更完了用のテンプレート
【templates/registration/password_change_done.html】
{% extends "common/base.html" %}
{% load static %}
{% block titele %}パスワード変更完了{% endblock %}
{% block content %}
<p><a href="{% url 'login' %}">ホームに戻る</a></p>
{% endblock %}
- 「ホームに戻る」には、ログイン画面へのリンクを紐づけています。
なお、このパスワード変更完了用のテンプレートを表示させると以下のようになります。
パスワード再設定
パスワード再設定機能のために、以下ファイルを作成します。
- templates/registration/password_reset_form.html
- パスワード再設定のメール送信用のテンプレート
- templates/registration/password_reset_done.html
- パスワード再設定のメール送信完了用のテンプレート
- templates/registration/password_reset_confirm.html
- パスワード再設定用のテンプレート
- templates/registration/password_reset_complete.html
- パスワード再設定完了用のテンプレート
- templates/registration/password_reset_subject.txt
- パスワード再設定のメール題名
- templates/registration/password_reset_email.html
- パスワード再設定のメール本文を指定するファイル
パスワード再設定の流れは以下のように有効なユーザのメールアドレスを使用します。
- パスワード再設定のメール送信用画面にアクセスし、メールアドレスを指定する。
- 指定したメールアドレスにパスワード再設定用のURLリンクが乗ったメールが送信される。
- メールに記載されているURLリンクにアクセスする。
- パスワード再設定画面にアクセスできるので、パスワードを再設定する。
※指定されたメールアドレスの有効性チェックは、Djangoのユーザ管理DBに登録されているメールアドレスかどうかでおこなってみるみたい。そのため、ユーザ登録時にメールアドレスを指定していないとパスワード再設定のメールがでないようです。
パスワード再設定のメール送信用のテンプレート
【templates/registration/password_reset_form.html】
{% extends "common/base.html" %}
{% load static %}
{% block titele %}パスワード再設定メール送信{% endblock %}
{% block content %}
<div>
<form method="post">
{% csrf_token %}
{{ form.as_p }}
<input type="submit" value="メール送信" class="btn btn-primary">
</form>
</div>
{% endblock %}
- 「
django.contrib.auth.form
」でフォームが規定されているので、form.as_p
を使って簡単にHTMLのフォームを生成しています。 - メール送信ボタンのデザインはBootstrap4を使っています。
なお、このパスワード再設定のメール送信用のテンプレートを表示させると以下のようになります。
パスワード再設定のメール送信完了用のテンプレート
【templates/registration/password_reset_done.html】
{% extends "common/base.html" %}
{% load static %}
{% block titele %}パスワード再設定メール送信完了{% endblock %}
{% block content %}
<p><a href="{% url 'login' %}">ホームに戻る</a></p>
{% endblock %}
- 「ホームに戻る」には、ログイン画面へのリンクを紐づけています。
なお、このパスワード再設定のメール送信完了用のテンプレートを表示させると以下のようになります。
パスワード再設定用のテンプレート
【templates/registration/password_reset_confirm.html】
{% extends "common/base.html" %}
{% load static %}
{% block titele %}パスワード再設定{% endblock %}
{% block content %}
<div>
<form method="post">
{% csrf_token %}
{{ form.as_p }}
<button type="submit" class="btn btn-primary">パスワード再設定</button>
</form>
</div>
{% endblock %}
- 「
django.contrib.auth.form
」でフォームが規定されているので、form.as_p
を使って簡単にHTMLのフォームを生成しています。 - パスワード再設定ボタンのデザインはBootstrap4を使っています。
なお、このパスワード再設定用のテンプレートを表示させると以下のようになります。
パスワード再設定完了用のテンプレート
【templates/registration/password_reset_complete.html】
{% extends "common/base.html" %}
{% load static %}
{% block titele %}パスワード再設定完了{% endblock %}
{% block content %}
<p><a href="{% url 'login' %}">ログインページ</a>に戻る</p>
{% endblock %}
- 「ログインページに戻る」には、ログイン画面へのリンクを紐づけています。
なお、このパスワード再設定完了用のテンプレートを表示させると以下のようになります。
パスワード再設定のメール題名とメール本文
【templates/registration/password_reset_subject.txt】
{% autoescape off %}
パスワード再設定を受け付けました
{% endautoescape %}
【templates/registration/password_reset_email.html】
{% autoescape off %}
To: {{ user.get_username }} 様
いつもご利用いただきありがとうございます。
パスワード再設定の手続きを受け付けました。
以下のURLにアクセスして、新しいパスワードを設定してください。
{{ protocol }}://{{ domain }}{% url 'password_reset_confirm' uid token %}
※このパスワード再設定用のURLの有効期限は3日間です。
このメールに覚えのない場合には、お手数ですがメールを破棄してください。
{% endautoescape %}
これら2つのファイルでパスワード再設定用のメールが作成されます。メール内容は以下のようになります。
[補足] Djangoでメール送信させるための設定
Djangoの設定ファイルに以下のように設定する必要がある。
【config/settings/base.py】
EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend'
EMAIL_HOST = 'smtp.gmail.com'
EMAIL_PORT = 587
EMAIL_HOST_USER = <Gメールのユーザ名>
EMAIL_HOST_PASSWORD = <Gメールのパスワード>
EMAIL_USE_TLS = True
- GメールでDjangoからメールを受信するためには、「安全性の低いアプリの許可」を行う必要があるので注意。
- 以下を参考
ユーザ登録
冒頭でも記載したとおり、Djangoのデフォルトのユーザ認証機能ではユーザ登録やユーザ情報の変更機能は搭載されていません。そのため、Djangoの管理画面からユーザ登録をします。
以下でまとめたので、参考にしてください。
ログインしてみる
ご自分のサイトのURLの後ろに「/accounts/login/」をつけて、ブラウザからアクセスします。例えば、runserverであれば「http://localhost:8000/accounts/login/」にアクセスします。
先ほど登録したユーザ名とパスワードでログインできるはずです。
[補足] ログインしないとアクセスできないアプリにするには?
ログインしないとアクセスできないアプリを作るためには以下の設定が必要です。
- クラスベースビューなら「LoginRequiredMixin」を継承してあげればOK
- 関数ベースビューなら「@login_required」デコレーターを指定すればOK
【クラスベースビュー】
from django.views.generic import View
from django.contrib.auth.mixins import LoginRequiredMixin
class XXXView(LoginRequiredMixin, View):
【関数ベースビュー】
from django.contrib.auth.decorators import login_required
@login_required
def View(request):
return render(request,"template/index.html")
Djangoのユーザ認証機能を改善したこと
Djangoのユーザ認証機能は最低限の機能しかないので、以下に改善したことをまとめました。よろしければご参考にしてください。
Djangoのユーザ認証機能のデザインを見直す
Djangoのユーザ認証機能にログイン試行回数制限を追加する
Djangoのユーザ認証機能にログイン有効期限を設定する
参考文献
広告
Djangoをやるなら以下の書籍がオススメです。
DjangoでWebアプリを開発するときの要点が分かりやすくまとめられています。
以上!
コメント