yynsmk's tech blog

何でもできる=何にもできない

Django標準の機能で実装する一番シンプルなユーザ認証

はじめに

Firebase等を使用せずに、Djangoにもともとあるライブラリのみでユーザー認証機能を作成します。
Djangoのプロジェクトがすでに立ち上がっており、テンプレートbase.htmlとそれを拡張したindex.htmlは最低限作られている前提で進めていきます。

ログイン・ログアウト

urlの設定

app/urls.pyに以下を記述します。
ログイン・ログアウトのViewはDjango側がdjango.contrib.authに用意してくれているので、それらをimportして使います。

from django.urls import path
from . import views
from django.contrib.auth import views as auth_views


app_name = "app"
urlpatterns = [
    path("", views.index, name="index"),
    path("login/", auth_views.LoginView.as_view(template_name="app/login.html"), name="login"),
    path("logout/", auth_views.LogoutView.as_view(), name="logout"),
]

settings.pyに以下を追記します。
<アプリ名>:<表示したいページ>という形でログイン関連のURLをDjangoに教えてあげます。

LOGIN_URL = 'app:login'            # ログイン時
LOGIN_REDIRECT_URL = 'app:index'   # ログイン後
LOGOUT_REDIRECT_URL = 'app:index'  # ログアウト後

ログインページの作成

login.htmlを以下のように作成します。

{% extends 'app/base.html' %}

{% block content %}

<h2>ログイン</h2>
<form method="POST">{% csrf_token %}
    {% if form.errors %}
        <p>ユーザー名またはパスワードが間違っています。もう一度入力してください。</p>
    {% endif %}
    <h2>ログイン</h2>
    <label>ユーザー名</label>
    <input name="username">
    <br>
    <label>パスワード</label>
    <input type="password" name="password">
    <br>
    <input type="submit" value="ログイン">
</form>

{% endblock %}

動作確認

localhost:8000/login/にアクセスして以下のようなシンプルなフォームが見れればOKです。

f:id:b_murabito:20190717002850p:plain

ログイン判定

ユーザーがログイン済みかどうかはUserオブジェクトのis_authenticatedフィールドの値によって判定できます。
使用例として、ユーザーがサイト訪問時にログイン済みであればログアウトボタンを、未ログインであればログインボタンとユーザー登録ボタンを表示するというのがあるでしょう。

{% if request.user.is_authenticated %}
<a href="{% url 'app:logout' %}">ログアウト</a>
{% else %}
<a href="{% url 'app:login' %}">ログイン</a>
<a href="{% url 'app:signup' %}">ユーザー登録</a>
{% endif %}

ユーザー登録

urlの設定

app/urls.pyに以下を記述します。

from django.urls import path
from . import views
from django.contrib.auth import views as auth_views


app_name = "app"
urlpatterns = [
    path("", views.index, name="index"),
    path("login/", auth_views.LoginView.as_view(template_name="app/login.html"), name="login"),
    path("logout/", auth_views.LogoutView.as_view(), name="logout"),
    path("signup/", views.signup, name="signup"),
]

Viewの作成

ユーザー登録のためのViewはあらかじめ用意されていないので自分で作ります。
app/views.pyに以下を記述してください。
ユーザー登録に必要なフォームはdjango.contrib.auth.formsUserCreationFormを使います。

from django.contrib.auth.forms import UserCreationForm
from django.contrib.auth import authenticate, login

def signup(request):
    if request.method == "POST":
        form = UserCreationForm(request.POST)
        if form.is_valid():
            new_user = form.save()
            input_username = form.cleaned_data("username")
            input_password = form.cleaned_data("password1")
            # ユーザーを認証する
            new_user = authenticate(username=input_username, password=input_password) 
            if new_user is not None:
                # ユーザーをログイン状態にする
                login(request, new_user)
                return redirect("app:index")
    else:
        form = UserCreationForm()
    return render(request, "app/signup.html", {"form": form})

ユーザー登録ページの作成

signup.htmlを以下のように作成します。

{% extends "app/base.html" %}

{% block content %}

<h2>ユーザー登録</h2>
<form method="POST" action="{% url 'app:signup' %}">{% csrf_token %}
    <label>ユーザー名</label>
    {{ form.username }}
    {{ form.username.errors }}
    <br>
    <label>パスワード</label>
    {{ form.password1 }}
    {{ form.password1.errors }}
    <br>
    <label>パスワード(確認)</label>
    {{ form.password2 }}
    {{ form.password2.errors }}
    <br>
    <input type="submit" value="登録する">
</form>

{% endblock %}

動作確認

localhost:8000/signup/にアクセスすると以下のようなシンプルなフォームが現れるはずです。

f:id:b_murabito:20190717003202p:plain