環境
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_changed
とpassword_changed_date
を用意しておいた。
また前回これを利用して、初回ログイン時にパスワードを強制変更させるようにした。
そして、今回はこれらの値を利用して、定期的にユーザにパスワード変更を強制させる。
パッケージのインストール
Advanced Python Scheduler(APScheduler)は、Pythonコードを1回だけまたは定期的にスケジュールできるPythonライブラリ。
pipコマンドでインストールする。
pip install APScheduler
手順1
以下のように記載する。
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
を更新する。
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_changed
がFalse
に更新されるのがわかる。
また前回の設定により、そのアカウントの次回ログイン時にパスワードの変更画面に強制的に遷移する。
参考
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での本人確認による解除