QueryDictをどうにかして拡張してハッシュ化したパスワードでログインしたかった話
パスワードのハッシュ化は基本
まあそりゃ平文で保存するはずないのであるユーザーがあるパスワードをつくったときはハッシュ化します
こんなmodels.pyがあるとする
from django.db import models class User(models.Model): name = models.CharField(u"名前", max_length=64) password = models.CharField(max_length=64) is_active = models.BooleanField(default=True) ctime = models.DateTimeField(u'登録日時',auto_now_add=True, editable=False) atime = models.DateTimeField(u'更新日時',auto_now=True, editable=False) def __unicode__(self): return self.name class Meta: db_table = 'User' @classmethod def register(cls, name, password): from schedule_proj.schedule.tools import Password user = cls.objects.create(name=name, password=Password.makeHash(password)) return user
内部で使われているPasswordというのはこちら
import hashlib class Password(object): @classmethod def makeHash(cls, password): return hashlib.sha1(password).hexdigest()
まあクラスにする必要もないかもしれないけど、要はhashlibを使ってhexdigestを記録しているだけ。
ここまでは簡単。問題はログイン
ログインするときに request.POST の内容で直接渡そうとするとこんな感じになってしまう
<QueryDict {'user':'hoge', 'password':'moge': 'csrftokenmiddleware':'hogehoge'}>
つまり request.POST.get('password') した値をつかってログインしようとしてもそれ自体はハッシュ化されてないために値が一致しない = ログインできないことになる
request.POST.copy()があった
結局こうした。もっとスマートな方法があるかもしれない
views.py
if request.method == "POST": #リクエストのコピーをとる copy_req = request.POST.copy() #ハッシュ化して上書きする copy_req['password'] = Password.makeHash(request.POST.get('password')) #フォームを渡すときにパスワードを上書きしたリクエストを送る form = LoginForm(copy_req) if not form.is_valid(): return HttpResponseRedirect(reverse('index')) #存在しないユーザーならindexに戻す if not User.objects.filter(name=form.cleaned_data['name']).count(): return HttpResponseRedirect(reverse('index')) request.session['session_user'] = User.objects.get(name=form.cleaned_data['name'])
request.POST自体はQueryDictオブジェクトであり、このインスタンスに代入することはできない(はず)なのでこうした
参考::ueBLOG | request.POSTの挙動
Djangoのrequest.POSTはdjango.http.QueryDictオブジェクトのインスタンスです。 QuersyDictオブジェクトはdjango.utils.datastructures.MultiValueDictを継承してます。 ではMultiValueDictは何かというとpythonの辞書型を継承してます。
通常のPythonの辞書はkeyとvalueが一対一ですが、MultiValueDictは名前の通りkeyに対し複数のvalueを持ちます。 持ち方としては内部で配列で持ち、値を返すときに一番最後の配列の要素を返すようになっています。
ちなみにQueryDictはインスタンスを作ったときに入れた値を変更するとエラーになるように拡張したMultiValueDictです。 request.POSTで得たデータを変更したデータを使う場合にrequest.POST.copy()をしなくてはこのためです。
そんなわけで
無事にハッシュ化された値でログインできましたとさ。ちゃんちゃん。
もっとスマートなやり方はあるような気がするんだけどねー。Django付属のcontrib.authみたいなところをちょっと覗いたけどわからなかった。