DjangoBrothers BLOG ✍️

2018/05/07

このエントリーをはてなブックマークに追加
Django モデル

Django 仮パスワードを生成して更新する

Webサービスを運営していると、仮パスワードを発行したい場面が出てくることがあります。

例えば、「自分のパスワードを忘れてしまったユーザーに対して、再ログインできるように仮パスワードを発行してメールで送ってあげる」場面なんかが考えられます。

仮パスワード発行の手順

やらなければいけないことは、主に以下の通りです。今回は1、2の手順を説明します。

  1. ランダムの文字列を作る。
  2. 1.で作った数字を対象ユーザーのパスワードとして保存する。
  3. 仮パスワードをメールなどでユーザーに報告する。

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です。