问题描述
我具有以下用于存储以前使用的哈希密码的模型:
class PasswordHistory(models.Model):
user = models.ForeignKey(User,on_delete=models.CASCADE)
password = models.CharField(max_length=128,unique=True)
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now = True)
在更改密码表单中,我要检查用户更改为的新密码是否在过去5次中没有使用。
这是我的表单验证:
class ProfileForm(forms.ModelForm):
password1 = forms.CharField(widget=forms.PasswordInput(),required=False)
password2 = forms.CharField(widget=forms.PasswordInput(),required=False)
class Meta:
model = Employee
user_id = None
def __init__(self,*args,**kwargs):
self.user_id = kwargs.pop('user_id',None)
super(ProfileForm,self).__init__(*args,**kwargs)
def clean_password2(self):
password1 = self.cleaned_data['password1']
password2 = self.cleaned_data['password2']
if password1 != password2:
raise forms.ValidationError('Passwords do not match.')
user = User.objects.get(pk=self.user_id)
hashed_password = make_password(password1)
password_histories = PasswordHistory.objects.filter(
user=user,password_hashed_password
)
if password_histories.exists():
raise forms.ValidationError('That password has already been used')
return password2
问题在于,即使我一次又一次地尝试使用相同的纯文本密码,密码也每次都不同。因此:
if password_histories.exists():
从不返回true。
如果过去的密码因盐而总是不同,该如何比较? 谢谢
解决方法
.set_password
函数确实不返回任何内容,它只是设置密码。就像您说的那样,哈希是基于(随机)盐的,因此哈希每次都会不同。因此,您应该使用.check_password(…)
function [Django-doc]来验证它是否与哈希变体匹配:
from django.contrib.auth.hashers import check_password
class ProfileForm(forms.ModelForm):
password1 = forms.CharField(widget=forms.PasswordInput(),required=False)
password2 = forms.CharField(widget=forms.PasswordInput(),required=False)
class Meta:
model = Employee
def __init__(self,*args,**kwargs):
self.user_id = kwargs.pop('user_id',None)
super(ProfileForm,self).__init__(*args,**kwargs)
def clean_password2(self):
password1 = self.cleaned_data['password1']
password2 = self.cleaned_data['password2']
if password1 != password2:
raise forms.ValidationError('Passwords do not match.')
user = User.objects.get(pk=self.user_id)
password_histories = PasswordHistory.objects.filter(
user=user
)
for pw in password_histories:
if check_password(password2,pw.password):
raise forms.ValidationError('That password has already been used')
return password2
因此,如果我们找到与给定的 raw 密码匹配的哈希密码,则可以返回password
。如果在for
循环结束时未找到任何此类密码,则可以返回password2
,否则会产生错误。