Система входа/аутентификации Django не совсем работает
Я новичок в django и у меня есть некоторые проблемы, то, что я пытаюсь сделать, это простая система входа в Django с пользовательским бэкендом и использованием postgresql в качестве основной базы данных.
Проблема в том, что моя функция аутентификации и входа в систему работает нормально, но пользователь на самом деле не вошел в систему, я написал пользовательское сообщение, чтобы сообщить мне, когда пользователь вошел в систему, и мой индекс защищен от анонимных пользователей, поэтому я в основном не могу получить доступ.
Этот код из моего views.py
@login_required(login_url='signin')
def index(request):
return render(request, 'index.html')
def signin(request):
now = datetime.now()
if request.method == 'POST':
username = request.POST['username']
password = request.POST['password']
print(username, password)
user = UserBackend.authenticate(UserBackend(), username=username, password=password)
if user is not None:
login(request, user, backend='core.backends.UserBackend')
print('Logged In') #### This print/checking is working fine!
return redirect('/')
#return render(request, 'index.html')
else:
messages.info(request, 'Invalid Username or Password! Try again')
return redirect("signin")
#else:
return render(request,'signin.html')
#user = auth.authenticate(username=username, password=password)
return render(request, 'signin.html')
Это мой пользовательский класс из models.py
class user(AbstractBaseUser):
id = models.AutoField(primary_key=True)
username = models.TextField()
real_name = models.TextField()
email = models.TextField()
password = models.TextField()
description = models.TextField()
last_login = models.DateField()
created_at = models.DateField()
is_staff = models.BooleanField(default=False)
is_active = models.BooleanField(default=True)
class Meta:
managed = False
db_table = 'user'
def __str__(self) -> str:
return self.username
И мой пользовательский бэкенд из backends.py
class UserBackend(ModelBackend):
def authenticate(self, **kwargs):
username = kwargs['username']
password = kwargs['password']
print('user: ', username)
print('pass: ', password)
#try:
user_ = user.objects.get(username=username)
try:
print(user_.check_password(password))
if user_.check_password(password) is True:
return user_
except user.DoesNotExist:
pass
def get_user(self, user_id):
try:
return user.objects.get(pk=user_id)
except user.DoesNotExist:
return None
Я попробовал изменить return в views.py на что-то вроде
return redirect(request.GET.get('next'))
но все еще не работает :(
)что мне делать?
Ключевым моментом является то, как вы используете свой Backend. Хотя, давайте начнем с самого начала...
Начиная с ваших моделей, вы без необходимости перезаписываете множество полей. В модели Django AbstractUser
есть эти поля, которые вы создаете. На самом деле, модель содержит следующие поля с валидаторами там, где это необходимо:
- имя пользователя
- first_name
- last_name
- is_staff по умолчанию false
- is_active по умолчанию true
- date_joined по умолчанию
timezone.now()
- last_login
- встроенная функция
get_full_name
(эквивалентная вашему полюreal_name
)
Также, id = models.AutoField(primary_key=True)
не обязательно, Django по умолчанию создает этот тип поля автоматически для каждой модели. Чаще всего это используется, когда вам нужно поле другого типа, как PK. Таким образом, простая модель, будет соответствовать вашим требованиям:
from django.db import models
from django.contrib.auth.models import AbstractUser
class User(AbstractUser):
description = models.TextField()
from django.contrib.auth.backends import ModelBackend
from django.contrib.auth.hashers import check_password
from django.contrib.auth import get_user_model
User = get_user_model()
class UserBackend(ModelBackend):
def authenticate(self, request, **kwargs):
username = kwargs['username']
password = kwargs['password']
try:
user = User.objects.get(username=username)
pwd_valid = check_password(password, user.password)
if pwd_valid:
return user
else:
return None
except User.DoesNotExist:
return None
Теперь о том, как его использовать. Цитируя документацию:
За кулисами Django ведет список "аутентификационных backends", которые он проверяет на подлинность. Когда кто-то вызывает django.contrib.auth.authenticate(), Django пытается аутентифицироваться через все свои бэкенды аутентификации. Если первый метод аутентификации не удается, Django пробует второй, и так далее, пока все бэкенды не будут были испробованы.
Список используемых бэкендов аутентификации указывается в параметре AUTHENTICATION_BACKENDS. Это должен быть список путей Python указывающих на классы Python, которые знают, как аутентифицироваться. Эти классы могут находиться в любом месте вашего пути к Python.
Итак, сначала нам нужно добавить AUTHENTICATION_BACKENDS в settings.py:
AUTH_USER_MODEL = 'core.User'
LOGIN_URL = '/signin'
AUTHENTICATION_BACKENDS = [
'core.auth.backends.UserBackend',
'django.contrib.auth.backends.ModelBackend'
]
Наконец, в файле views.py мы вызываем функции точно так же, как и в обычной функции login:
from django.shortcuts import render, redirect
from django.contrib.auth.decorators import login_required
from django.contrib.auth import login, authenticate
from django.contrib import messages
# Create your views here.
@login_required
def index(request):
return render(request, 'index.html')
def signin(request):
if request.method == 'POST':
username = request.POST['username']
password = request.POST['password']
user = authenticate(request, username=username, password=password)
if user is not None:
login(request, user)
# Confirm that backend is UserBackend
print(user.backend)
return redirect('core:index')
else:
messages.info(request, 'Invalid Username or Password! Try again')
return redirect("core:signin")
return render(request, 'signin.html')