Django не регистрируется должным образом при использовании пользовательского бэкенда и моделей
Я пытаюсь реализовать пользовательский бэкенд аутентификации в Django, но он ведет себя очень странно. Пользовательский бэкенд аутентифицируется по модели, отличной от обычной модели Django User, и после успешной проверки предоставленных учетных данных бэкенд получает или создает наш обычный экземпляр Django User, который он возвращает. Вход, тем не менее, не работает.
Из документации я узнал, что мне просто нужно наследовать django.contrib.auth.backends.BaseBackend
и переопределить метод authenticate()
, что я и сделал. Как я уже говорил, пользовательский метод authenticate()
в основном проверяет набор учетных данных (имя пользователя и пароль) на те, которые хранятся в базе данных (пользовательская модель, не django.contrib.auth.models.User
), и если они совпадают, то получает или создает экземпляр django.contrib.auth.models.User
через прокси-модель, которую я назвал Profile
; в основном модель Profile
имеет ссылки на django.contrib.auth.models.User
и мою пользовательскую модель. Однако при входе в систему я продолжаю перенаправляться на страницу входа в систему (Это как будто Django регистрирует меня, но не устанавливает что-то где-то, чтобы при попытке доступа к защищенному ресурсу я перенаправлялся обратно на страницу входа в систему). Также, когда я вхожу в систему, используя объект django.contrib.auth.models.User
, все работает нормально, и я могу получить доступ к защищенным страницам. Ниже перечислены причины, по которым я выбрал этот подход к аутентификации.
- Я работаю с существующей базой данных, которая имеет свои собственные таблицы пользователей с очень отличной схемой, чем та, которую предоставляет Django. (Фактически, единственные поля в этой системной таблице пользователей, похожие на таблицу Django, это имя пользователя и пароль) .
- Я использовал команду управления Django
inspectb
для воссоздания моделей, которые я строго проинструктирован оставить неуправляемыми, ну, знаете,manage=False
вmeta class
модели. В принципе, я не могу наследоватьAbstractUser
от Django, так как это потребует добавления новых полей.
Так что лучший подход, который я мог придумать, это использовать прокси-модель, которая свяжет как django.contrib.auth.models.User
, так и мои пользовательские неуправляемые модели с пользовательским бэкендом аутентификации.
Я пробовал следить за определенными переменными, такими как словарь request.session
и request.user
, все они установлены, но все равно не могу успешно войти в систему. Также, когда я использую учетные данные, которых нет ни в одной из двух моделей, я получаю сообщение Invalid Credentials
на странице входа (желательное поведение).
На самом деле, мой пользовательский метод authenticate()
работает нормально и возвращает действительного пользователя, проблема, я думаю, кроется в django.contrib.auth.login
. В чем может быть проблема?
Вот мой authenticate
метод
def authenticate(self, request, username=None, password=None):
try:
c_user = CustomUser.objects.get(username=username)
except CustomUser.DoesNotExist:
return None
#pwd_valid = check_password(password, user.password)
if not c_user.password==password:
return None
#Get and return the django user object
try:
profile = Profile.objects.get(custom_user=c_user)
user = profile.user
#Create user if profile has none
if not user:
user = User.objects.create(
username=''.join(secrets.SystemRandom().choice(string.ascii_uppercase + string.digits) for _ in range(24))
)
profile.user = user
profile.save()
#Create new profile if none exists
except Profile.DoesNotExist:
#Create new user for the profile
user = User.objects.create(
username=''.join(secrets.SystemRandom().choice(string.ascii_uppercase + string.digits) for _ in range(24))
)
Profile.objects.create(
user = user,
custom_user = c_user
)
return user
Вот как я добавил пользовательский бэкенд в settings.py
AUTHENTICATION_BACKENDS = [
'Authentication.custom.CustomAuth',
'django.contrib.auth.backends.ModelBackend'
]
Не могу поверить, что отвечаю на свой собственный вопрос. После долгих отладок и чтения документации я понял, что не переопределил get_user
метод django.contrib.auth.backends.BaseBackend
, поэтому всегда вызывался метод по умолчанию, который возвращает None
. Я реализовал это, и все заработало как шарм.