Reputation: 31
I work with django and store user passwords as hashed values created with make_password. When I run check_password, I always get a false return and I am out of ideas how to solve this.
Any help would be much appreciated.
My user registration looks like this:
def user_reg_view(request):
form = UserForm(request.POST or None)
if form.is_valid():
password = hashers.make_password(form.cleaned_data.get('password'))
fname = form.cleaned_data.get('first_name')
lname = form.cleaned_data.get('last_name')
email = form.cleaned_data.get('email')
company_id = form.cleaned_data.get('company')
User.objects.create_user(
email = email,
password=password,
first_name = fname,
last_name = lname,
username = email,
company_id = company_id)
form = UserForm()
var = {'form': form}
return render(request, 'user_registry.html', var)
And my login function part that fails looks like so (assume the user exists and password entered is always the same):
def login_view(request):
form = LoginForm(request.POST or None)
if form.is_valid():
username = form.cleaned_data.get('username')
user = User.objects.get(username=username)
password = form.cleaned_data.get('password')
encoded_password = user.password
print(hashers.make_password(password) == user.password)
#returns false
print(hashers.check_password(password=password, encoded=hashers.make_password(password), setter=None))
#returns true
print(hashers.check_password(password=password, encoded=encoded_password))
# returns false
I do not get how the first print differs from the second, of course the password hash generated differs each time for the same string but shouldn't check_password be able to process that?
In case the error might be in the register form values passed, here's also a snippet of that function:
class UserForm(forms.ModelForm):
company = forms.CharField(max_length=50, label='', widget=forms.TextInput(attrs={'placeholder': 'your company'}))
first_name = forms.CharField(max_length=30, label='', widget=forms.TextInput(attrs={'placeholder': 'first name'}))
last_name = forms.CharField(max_length=30, label='', widget=forms.TextInput(attrs={'placeholder': 'last name'}))
email = forms.CharField(max_length=40, label='', widget=forms.TextInput(attrs={'placeholder': 'email'}))
password1 = forms.CharField(
strip=False,
widget=forms.PasswordInput(attrs={'autocomplete': 'new-password'}),
validators=[validate_password],
label='password')
password2 = forms.CharField(
label= 'please confirm password',
widget=forms.PasswordInput(attrs={'autocomplete': 'new-password'}),
strip=False
)
class Meta:
model = User
fields = ['first_name', 'last_name', 'email']
def clean_password2(self):
password1 = self.cleaned_data.get("password1")
password2 = self.cleaned_data.get("password2")
if password1 and password2 and password1 != password2:
raise forms.ValidationError('password_mismatch')
return password2
Upvotes: 1
Views: 919
Reputation: 318
Django is hashing the value you provided again when you call create_user()
, you can check out this answer, where it says that you can first use create()
and then save()
the password as it is, without hashing the value you provide.
Upvotes: 1
Reputation: 31
Double hashing was one of the problems, another one was that I was unknowingly hashing a None value (instead of the actual entered password).
In my registration form (User Form) I work with password1 and password2, after matching them I return password2. In my user_reg_view where I create the user, however, I was setting the password like so:
password = form.cleaned_data.get('password')
This should have been password2 or password1, password was set to None and did not throw an error.
Upvotes: 0
Reputation: 21812
The create_user
method hashes the password that is passed to it as an argument. Meaning you are hashing the plain text password two times before storing it to the database. Furthermore no need to use hashers.check_password
simply use the authenticate
function - Django docs
So your registration view would be:
def user_reg_view(request):
form = UserForm(request.POST or None)
if form.is_valid():
password = form.cleaned_data.get('password')
fname = form.cleaned_data.get('first_name')
lname = form.cleaned_data.get('last_name')
email = form.cleaned_data.get('email')
company_id = form.cleaned_data.get('company')
User.objects.create_user(
email = email,
password=password,
first_name = fname,
last_name = lname,
username = email,
company_id = company_id)
form = UserForm()
var = {'form': form}
return render(request, 'user_registry.html', var)
And your login view:
from django.contrib.auth import authenticate, login
def login_view(request):
form = LoginForm(request.POST or None)
if form.is_valid():
username = form.cleaned_data.get('username')
password = form.cleaned_data.get('password')
user = authenticate(username=username, password=password)
if user is not None:
login(request, user) # login if valid credentials
# other code
Upvotes: 1