2018/05/07
Django モデルDjango 仮パスワードを生成して更新する
Webサービスを運営していると、仮パスワードを発行したい場面が出てくることがあります。
例えば、「自分のパスワードを忘れてしまったユーザーに対して、再ログインできるように仮パスワードを発行してメールで送ってあげる」場面なんかが考えられます。
仮パスワード発行の手順
やらなければいけないことは、主に以下の通りです。今回は1、2の手順を説明します。
- ランダムの文字列を作る。
- 1.で作った数字を対象ユーザーのパスワードとして保存する。
- 仮パスワードをメールなどでユーザーに報告する。
1. ランダムの数字を作る
まずは、仮パスワードとなる、ランダムの数字を生成します。
文字列の一覧はPythonのstringモジュールを使って取得できるので、これをrandomモジュールでランダムに並べてあげれば良いです。
stringモジュールで文字列を取得
import string
print (string.ascii_letters)
# abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ
print (string.digits)
# 0123456789
上のようにstringモジュールから得られる文字列を、ランダムに並べます。
ランダムに取得した文字を結合
import string, random
print (''.join([random.choice(string.ascii_letters + string.digits) for i in range(8)]))
# ランダムな英数字 8桁
random.choiceで、文字列の中から1つだけランダムに文字を取得。リスト内包表記のfor文でその作業を8回繰り返して、8つの文字からなるリストを作ります。そして、.joinで8つの文字を結合します。
これで、8桁のランダム英数字が完成です。
Userモデルが、BaseUserManagerを使っている場合はmake_random_password
メソッドを使う方法もあります。
make_random_passwordメソッドでランダム文字列を生成
>>> User.objects.make_random_password()
'Y4H9zjs4mr'
>>> User.objects.make_random_password()
'sMh32aiR1'
2. ユーザーのパスワードを更新する
ランダムな文字列を生成したら、それをユーザーのパスワードとして上書きしてあげます。
フィールドの値をアップデートしたい場合、通常以下のようになります。
ユーザーのageフィールドを更新
import User
# オブジェクトを取得してsave()で上書き保存
def age(request):
user = User.objects.get(id=1)
user.age = 25
user.save()
# クエリセットを取得してupdate()で上書き保存
def age(request):
user = User.objects.filter(id=1)
user.update(age=25)
しかし、パスワードの更新は上のようにしてもエラーが出てしまいます。パスワードは極めて重要なデータであるため、ちょっと違った処理が必要になります。
以下のようにset_passwordメソッドを使います。これは、Userオブジェクトの元となっている、AbastractBaseUserクラス内で定義されているメソッドになります。ソースコード
ユーザーのパスワードを変更
import User
def change_password(request):
user = User.objects.get(id=1)
user.set_password('NewPassword')
user.save()
set_passwordの引数'NewPassword'が新しいパスワードとなります。
ここに、1で作った、仮パスワードをセットします。
仮パスワードを保存
import User
import string, random
def change_password(request):
temporary_password = (''.join([random.choice(string.ascii_letters + string.digits) for i in range(8)]))
user = User.objects.get(id=1)
user.set_password(temporary_password)
user.save()
あとは、仮パスワードをメールでユーザーに飛ばすなどすればOKです。