Djangoでタスク管理アプリ開発(To-Doリスト)⑥ ~認証機能 後半編~

プログラミング
Masa
Masa

こんにちは!Masaです。

今回は認証機能実装の後半編を行います!

この記事でわかること
  • タスク管理アプリの作成方法
  • 基本的なDjangoによるアプリ作成
  • Django搭載認証機能の実装方法

この記事は「Django開発入門」を参考にしています。
より詳しくDjangoを学びたい方におすすめしたい1冊です!

前回のおさらい

前回は認証機能を裏側部分をメインに実装しました。

Djangoでタスク管理アプリ開発(To-Doリスト)⑤ ~認証機能 前半編~
PythonとDjangoを使用してタスク管理アプリ(To_Doリスト)を作成しています。今回はタスクを締め切り前後での振り分けと日付順の並び替えを行っています。フィルターを使ってきれいにプログラムできています。

今回は表側であるテンプレートを作成し、認証機能を完成させたいと思います!

※記事中のコードに不備があるかもしれません。
 最新のコードはこちらにあるので、エラーなど出たらこちらも見てみてください。

テンプレートの作成

django-allauthはデフォルトでテンプレートがあります
今回は不要な機能などをそぎ落とすため、テンプレートをカスタマイズします。

↓デフォルトのテンプレート

django-allauth/allauth/templates/account at main · pennersr/django-allauth
Integrated set of Django applications addressing authentication, registration, account management as well as 3rd party (...

”templates”フォルダ内に“account”フォルダを作成し、この中にHTMLファイルを格納します。
ファイル名は決まっており、間違えるとカスタムテンプレートが反映されないため気を付けてください。

認証機能を実装する場合、以下の4つの機能は最低限必須です。

認証に必要な機能
  1. ログイン
  2. ログアウト
  3. アカウント作成(サインアップ)
  4. パスワードリセット

ログインに関しては、メールアドレスとパスワードを入力してボタンをクリックするだけなので、テンプレートは1枚で十分です。

ログアウトはsettings.pyでも記載した通り、「ログアウトしますか?」という確認画面を入れないため、今回はテンプレートは不要です。

アカウント作成、パスワードリセットは前回の記事の最後に記載した通り、いくつかのステップを踏む必要があるため、テンプレートは複数枚になります。

それぞれ作成していきましょう。

ログインテンプレート

ログインテンプレートは“login.html”です。

{% extends "to_do_list/base.html" %}
{% load django_bootstrap5 %}

{% block content %}
<div class='container'>
  <div class='row'>
    <div class='mt-5 mb-4 col-sm-12 col-md-6 mx-auto'>
      <form class="login" method="POST" action="{% url 'account_login' %}">
        {% csrf_token %}
        {% bootstrap_form form %}
        <div class='mt-3'>
          <button class='btn btn-outline-primary' type='submit'>ログイン</button>
        </div>
      </form>
      <div class='mt-3'>
        <p><a class='button secondaryAction' href="{% url 'account_signup' %}">アカウント作成はこちら</a></p>
      </div>
      <div class='mt-3'>
        <p><a class='button secondaryAction' href="{% url 'account_reset_password' %}">パスワード忘れましたか?</a></p>
      </div>
    </div>
  </div>
</div>
{% endblock %}

簡単に解説します。

  • 2行目:前回の記事でインストールした”django-bootstrap5″を読み込んでいます
  • 8行目:”action=”以降のリンクにログインボタンをクリック後リクエストします
  • 10行目:このような形にするとフォームが装飾されます
  • 16行目:アカウント作成ページに行くリンクを貼っています
  • 19行目:パスワード再設定ページへのリンクを貼ってあります

特に難しい点はなく、この後作成するテンプレートも似たものが多いため上手に使いまわすと効率よく作成できます。



アカウント作成のテンプレート

アカウント作成は以下の手順で行います。

  1. メールアドレス、パスワードを入力
  2. 入力したメールアドレス宛に確認メールが送られる
  3. 届いたメールのURLをクリックしてユーザ登録完了

よって3つのテンプレートを作成します。

1つ目はアカウント用のメールアドレス、パスワードを入力するテンプレートです。
テンプレート名は“signup.html”を作成してください。

{% extends "to_do_list/base.html" %}
{% load django_bootstrap5 %}

{% block content %}
<div class='container'>
  <div class='row'>
    <div class='mt-5 mb-4 col-sm-12 col-md-6 mx-auto'>
      <form method="POST" action="{% url 'account_signup' %}">
        {% csrf_token %}
        {% bootstrap_form form %}
        <div class='mt-3'>
          <button class='btn btn-outline-primary' type='submit'>登録</button>
        </div>
      </form>
    </div>
  </div>
</div>
{% endblock %}

”login.html”時とほぼ変わりがありませんね。

2つ目は「登録」ボタンをクリックした後、メールを送信しましたと表示するテンプレートです。
テンプレート名は”verification_sent.html”となります。

{% extends "to_do_list/base.html" %}
{% load django_bootstrap5 %}

{% block content %}
<div class='container'>
  <div class='row'>
    <div class='mt-5 col-sm-12 col-md-6 mx-auto'>
      <div class='mb-4'>
        <h1>メールを送信しました</h1>
      </div>
        <p>メールに記載されているリンクをクリックし、ユーザ登録を完了させてください。</p>
        <p>メールが届かない場合はご連絡ください。</p>
    </div>
  </div>
</div>
{% endblock %}

“verification_sent.html”に関してはフォーム等もないので、簡単だと思います。

3つ目はメールに記載されているリンクを開くと表示されるページです。
このページでは登録ボタンをクリックし、アカウントの登録が完了となります。

テンプレート名は”email_confirm.html”です。

{% extends "to_do_list/base.html" %}
{% load django_bootstrap5 %}

{% block content %}
<div class='container'>
  <div class='row'>
    <div class='mt-5 mb-4 col-sm-12 col-md-6 mx-auto'>
    {% if confirmation %}
        <div class="mb-4">
            <h1>ユーザ確認</h1>
        </div>
        <p>以下のボタンをクリックするとユーザ登録が完了します</p>
        <form method="POST" action="{% url 'account_confirm_email' confirmation.key %}">
            {% csrf_token %}
            <div class='mt-3'>
                <button class='btn btn-outline-primary' type='submit'>完了</button>
            </div>
        </form>
    {% else %}
        {% url 'account_email' as email_url %}
        <div class="mb-4">
            <h1>リンクの有効期限切れ</h1>
        </div>
        <p>再申請を行ってください<p>
        <div class='mt-3'>
            <a class='btn btn-outline-primary' href="{{ email_url }}">再申請</a>
        </div>
    {% endif %}
    </div>
  </div>
</div>
{% endblock %}

ここでは条件文を使用し、①リンクが有効な場合、②リンク切れの場合を作成しています。

リンクの有効時間がどのぐらいなのかわかりませんでした。(開発用サーバでは1日経過してもリンクは有効でした)
また、再申請ボタンのリンクが”account_email”となっている理由は、最初のメールアドレスを入力した時点でアカウントは作成されており、”account_signup”では同じメールアドレスを使用して再度アカウントを作成することができません。
“account_email”を使用することで、アカウント情報の整合性を保っている(アカウントを削除する等)のではないかと考えています。

ただ正確ではないため、知っている人がいれば教えていただきたいです。

パスワードリセットのテンプレート

パスワードのリセットは以下の手順で行います。

  1. 再設定用メールを送りメールアドレスを入力
  2. メールが届いたらULをクリックしパスワードの再設定を行う

手順は2段階ですが、テンプレートは4つ必要になります。

  1. メールアドレスを入力するページ
  2. メールを送りましたと知らせるページ
  3. パスワードを再設定するページ
  4. パスワード再設定が完了しましたと知らせるページ

1つ目はメールアドレスを入力するページを作成します。
テンプレート名は”password_reset.html”です。

{% extends "to_do_list/base.html" %}
{% load django_bootstrap5 %}


{% block content %}
<div class='container'>
  <div class='row'>
    <div class='mt-5 mb-4 col-sm-12 col-md-6 mx-auto'>
      <h1>パスワードリセット</h1>

      {% if user.is_authenticated %}
      {% include 'account/snippets/already_logged_in.html' %}
      {% endif %}

      <p>登録済みのメールアドレスを入力してください</p>
      <p>パスワードリセット用のメールを送信します</p>  
      <form method="POST" action="{% url 'account_reset_password' %}">
        {% csrf_token %}
        {% bootstrap_form form %}
        <div class='mt-3'>
          <button class='btn btn-outline-primary' type='submit'>送信</button>
        </div>
      </form>
    </div>
  </div>
</div>
{% endblock %}

11~13行目の部分は、ユーザがログインしている状態だと「ログインしています」と注意を出してくれます。

2つ目はメールアドレスを入力した後、メールを送信しましたと表示するページです。
テンプレート名は”password_reset_done.html”です。

{% extends "to_do_list/base.html" %}
{% load django_bootstrap5 %}

{% block content %}
<div class='container'>
  <div class='row'>
    <div class='mt-5 mb-4 col-sm-12 col-md-6 mx-auto'>
      <h1>パスワード再設定用メールを送信しました</h1>
    </div>
  </div>
</div>
{% endblock %}

3つ目は送られてきたメールのリンクを開き、新しいパスワードを設定するページです。
テンプレート名は”password_reset_from_key.html”です。

{% extends "to_do_list/base.html" %}
{% load django_bootstrap5 %}

{% block content %}
<div class='container'>
  <div class='row'>
    <div class='mt-5 mb-4 col-sm-12 col-md-6 mx-auto'>
      <h1>{% if token_fail %}不正トークン{% else %}新しいパスワードを入力{% endif %}</h1>

      {% if token_fail %}
      {% url 'account_reset_password' as passwd_reset_url %}
      <p>このリンクは無効になっています。</p>
      <p>再申請してください</p>
      <div class='mt-3'>
        <a class='btn btn-outline-primary' href="{{ passwd_reset_url }}">再申請</a>
      </div>
      {% else %}
      <form method="POST" action="{{ action_url }}">
        {% csrf_token %}
        {% bootstrap_form form %}
        <div class='mt-3'>
          <button class='btn btn-outline-primary' type='submit'>再登録</button>
        </div>
      </form>
      {% endif %}
    </div>
  </div>
</div>
{% endblock %}

こちらもリンクが有効な場合と有効でない場合の条件で表示内容を変更しています。

最後にパスワードを変更しましたと表示するページです。
テンプレート名は”password_reset_from_key_done.html”です。

{% extends "to_do_list/base.html" %}
{% load django_bootstrap5 %}

{% block content %}
<div class='container'>
  <div class='row'>
    <div class='mt-5 mb-4 col-sm-12 col-md-6 mx-auto'>
      <h1>パスワードが変更されました</h1>
      <a href="{% url 'account_login' %}">ログインはこちら<a>
    </div>
  </div>
</div>
{% endblock %}

以上で認証用テンプレートの作成が完了です。



ログイン/ログアウトボタンの配置

現在トップページ(index.html)にアクセスするとメールアドレスとパスワードを入力する画面が表示される仕様だと思います。

これは問題ありませんが、ログイン後にログアウトしたいときやアカウント作成のページからログイン画面に飛ぶ方法が今のところありません。

よってログインしていないときはログインボタンを、ログイン中はログアウトボタンを表示するようにしましょう。

追記するテンプレートは”base.html”です。

<nav class="navbar navbar-light" style="background-color: #4169e1;">
      <span class="navbar-brand mb-0 h1 mx-auto" style="color: white;">タスク管理アプリ</span>
      {% if user.is_authenticated %}
        <a type="button" class="btn btn-light" href="{% url 'account_logout' %}">ログアウト</a>
      {% else %}
      <a type="button" class="btn btn-light" href="{% url 'index' %}">ログイン</a>
      {% endif %}
    </nav>

ナビゲーションバー部分を上記のようにしましょう。

これでログイン状況によって表示されるボタンが変わります。



まとめ

前回と今回で認証機能を実装しましたが、まだ不完全なことが判明しました。

現在、登録したタスクはどのアカウントでログインしても同じものが表示されてしまします。
いわばタスクの共有みたいになっています。

次回の記事ではこの問題は修正し、タスクと作成者の関連付けを行いたいと思います。

↓次回の記事

作成中

コメント

タイトルとURLをコピーしました