0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

Django 一定期間パスワードを変更していないユーザにパスワード変更を強制する

Last updated at Posted at 2022-02-11

環境

Windows 11 Home
Python 3.10.2
Django 4.0.2
venv利用あり
(PyPI)
APScheduler==3.8.1
※関連記事 第1回, 第2回が完了していること

関連記事

Django 第1回:Django Custom User Model の作成
Django 第2回:Django 初回ログイン時にパスワード変更を強制する
Django 第3回:Django 一定期間パスワードを変更していないユーザにパスワード変更を強制する 今回
Django 第4回:Django ランダムかつ有効期限のあるURLを生成し、上位者に承認してもらいアカウントを発行する 
Django 第5回:Django パスワード試行回数ロックとランダムかつ有効期限付きURLでの本人確認による解除

背景

一定期間、たとえば90日経過したらパスワード変更を促したい場合がある。
これに関してはセキュリティ的に意味があるかの議論は別問題として、その機能を実装する。

前々回の記事でカスタムユーザモデルを作成し、パラメータとしてpassword_changedpassword_changed_dateを用意しておいた。
また前回これを利用して、初回ログイン時にパスワードを強制変更させるようにした。
そして、今回はこれらの値を利用して、定期的にユーザにパスワード変更を強制させる。

パッケージのインストール

Advanced Python Scheduler(APScheduler)は、Pythonコードを1回だけまたは定期的にスケジュールできるPythonライブラリ。
pipコマンドでインストールする。
pip install APScheduler

手順1

users 配下に update.py を作成する。
image.png

以下のように記載する。

users\update.py
import datetime
from apscheduler.schedulers.background import BackgroundScheduler
from .models import User # 作成したCustom User Model

def longTimeNoChangePassword():
    """一定期間パスワード変更をしていないユーザに次回アクセス時パスワード変更を強制させる"""
    # 期間をここでは3か月=93日とする
    today = datetime.date.today()
    xday1 = datetime.timedelta(days = 93)
    xdaybefore1 = today - xday1
    xday2 = datetime.timedelta(days = 92)
    xdaybefore2 = today - xday2

    # 対象ユーザを検索(フィルター)し、対象ユーザのステータスを更新する
    queryset = User.objects.filter(password_changed_date__range = [xdaybefore1, xdaybefore2], password_changed = True)
    for query in queryset:
        query.password_changed = False
        query.save()


def start():
    """指定スケジュールで実行"""
    scheduler = BackgroundScheduler()
    scheduler.add_job(longTimeNoChangePassword, trigger='cron', hour='22', minute='00', misfire_grace_time=60*60)
    scheduler.start()

解説1

  • objects.filter(password_changed_date__range = [xdaybefore1, xdaybefore2]では
    パラメータpassword_changed_dateを範囲で検索するために__range = [xdaybefore1, xdaybefore2]という表記を利用している。
    __range(アンダーバー2個)でレンジ扱いとなる。
    今回password_changed_dateを日時側としてしまったため、yyyy/mm/ddではヒットせず、yyyy/mm/dd~yyyy/mm/dd-1の日付の範囲でヒットさせることにした。

  • cronでの時刻指定の詳細は備考1の公式を参照のこと。

  • misfire_grace_timeはジョブの起動ずれをどこまで許容するか。単位は秒。

手順2

users 配下の apps.py を更新する。

users\apps.py
from django.apps import AppConfig

class UsersConfig(AppConfig):
    default_auto_field = 'django.db.models.BigAutoField'
    name = 'users'

    # 追加
    def ready(self):
        """起動時に呼び出される"""
        from .update import start
        start()

解説2

先ほどのupdate.pyのstart関数を呼び出している。

確認

適当なアカウントを93日前にして確認すると、password_changedFalseに更新されるのがわかる。
また前回の設定により、そのアカウントの次回ログイン時にパスワードの変更画面に強制的に遷移する。

参考

apscheduler.triggers.cron
apscheduler で add_job するときは misfire_grace_time の指定が必須
Django 第1回:Django Custom User Model の作成
Django 第2回:Django 初回ログイン時にパスワード変更を強制する
Django 第3回:Django 一定期間パスワードを変更していないユーザにパスワード変更を強制する
Django 第4回:Django ランダムかつ有効期限のあるURLを生成し、上位者に承認してもらいアカウントを発行する  
Django 第5回:Django パスワード試行回数ロックとランダムかつ有効期限付きURLでの本人確認による解除

0
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?