Django не может пройти аутентификацию или хэширование пароля неверно
Я использую пользовательскую модель пользователя, поэтому я могу аутентифицироваться, используя электронную почту вместо имени пользователя.
from django.db import models
from django.contrib.auth.models import (
AbstractBaseUser,
BaseUserManager,
PermissionsMixin,
)
class UserManager(BaseUserManager):
def create_user(
self,
email,
password,
confirm_code=None,
username=None,
role=None,
):
user = self.model(email=self.normalize_email(email))
user.set_password(password)
user.confirm_code = confirm_code
user.save()
return user
def create_superuser(self, email, password, role, username=None):
user = self.model(email=self.normalize_email(email))
user.set_password(password)
user.role = role
user.is_staff = True
user.is_active = True
user.is_superuser = True
user.save()
return user
class User(AbstractBaseUser, PermissionsMixin):
EM = "EM"
SM = "SM"
DH = "DH"
ST = "ST"
ROLES = [
(EM, "Executive Management"),
(SM, "Senior Management"),
(DH, "Department Head"),
(ST, "Staff Member"),
]
objects = UserManager()
role = models.CharField(max_length=2, choices=ROLES, default=US, blank=True)
username = models.CharField(max_length=20, unique=True, blank=True, null=True)
email = models.EmailField(max_length=255, unique=True)
slug = models.SlugField(blank=True, null=True)
confirm_code = models.CharField(max_length=20, null=True, blank=True)
is_active = models.BooleanField(default=False)
is_staff = models.BooleanField(default=False)
has_profile = models.BooleanField(default=False)
email_verified_at = models.DateTimeField(auto_now=False, null=True, blank=True)
code = models.CharField(max_length=8, null=True, blank=True)
created_at = models.DateTimeField(auto_now_add=True, verbose_name="Created at")
updated_at = models.DateTimeField(auto_now=True, verbose_name="Updated at")
class Meta:
verbose_name = "User"
verbose_name_plural = "Users"
ordering = ["username"]
db_table = "users"
def get_absolute_url(self):
return f"{self.slug}"
USERNAME_FIELD = "email"
REQUIRED_FIELDS = ["role"]
Когда я регистрирую пользователя, он создается в базе данных правильно, и пароль хэшируется, я полагаю, правильно, потому что я вижу хэш, а не необработанный пароль. Вот метод, который я использовал для регистрации пользователя:
@api_view(["POST"])
def RegisterUser(request, *args, **kwargs):
code = []
numbers = range(7)
for num in numbers:
code.append(randint(0, 9))
email = request.data["email"]
confirmemail = request.data["confirmemail"]
password = request.data["password"]
confirmpassword = request.data["confirmpassword"]
errors = []
if email != confirmemail:
errors.append("emailmatch")
return Response("Emails do not match", status=500)
if confirmpassword != password:
errors.append("passmatch")
return Response("Password do not match", status=500)
if User.objects.filter(email=email):
errors.append("emailexists")
return Response("User is already registered", status=500)
else:
pass
if len(errors) > 0:
return Response(False)
else:
password_to_save = make_password(password)
confirm_code = "".join(str(e) for e in code)
user = User.objects.create_user(
email=email, password=password_to_save, confirm_code=confirm_code
)
token = Token.objects.create(user=user)
from_email = "info@website.com"
link = f"http://127.0.0.1:8000/api/v1/users/confirm/{user.id}/{token}/"
context = {"link": link, "code": code}
template = get_template("emails/welcome.html").render(context)
subject = "Successfully registered"
message = "Welcome to website"
try:
send_mail(
subject,
message=message,
from_email=from_email,
recipient_list=[email],
html_message=template,
)
except:
return Response("Could not send mail")
serializer = RegisterSerializer(user)
return Response(serializer.data)
У меня есть пользовательский бэкенд для аутентификации пользователя с использованием электронной почты вместо имени пользователя, и вот что это:
class EmailBackend(ModelBackend):
def authenticate(self, request, **kwargs):
email = kwargs.get("email", None)
user = User.objects.get(email=email)
if user:
breakpoint()
if user.check_password(kwargs.get("password", None)):
return user
else:
return None
else:
User.DoesNotExist
return None
Просто не работает, и я не могу войти в систему. Пользователь активен! Если я сделаю breakpoint(), как показано здесь, и проверю пароль вручную, введя необработанный пароль в user.check_password('password'), то он вернет false. Разве check_password не должен хэшировать введенный пароль и сравнивать его с хэшем в базе данных или как это работает?
Это работает:
password = "hello"
saved = make_password(password)
true = check_password(password, saved)
Так почему же это не работает в моем бэкенде Authenticate, который является точно таким же?
Нужно ли мне использовать другой алгоритм хэширования или что?
Что я должен делать в таком случае и как я могу аутентифицировать пользователя? Есть ли другой способ сравнить пароль, введенный пользователем на форме, и хэшированный пароль, сохраненный в базе данных?
Вы используете функцию set_password
в create_user
в своем менеджере. Этот метод сам вызывает функцию make_password
.
Таким образом, когда вы передаете хэшированный пароль, сгенерированный через make_password
в create_user
, этот хэшированный пароль будет снова хэширован в функции set_password
.
Поэтому нет необходимости вызывать make_password
самостоятельно. Просто передайте обычный пароль в метод create_user
.