Django rest framework JWT и пользовательский бэкэнд аутентификации
У меня есть пользовательская модель пользователя, и я создал пользовательский бэкэнд аутентификации. Я использую http://www.django-rest-framework.org/ и django rest framework JWT для аутентификации токена.
Модель пользователя:
class User(AbstractBaseUser, PermissionsMixin):
email = models.EmailField(
unique=True,
max_length=254,
)
first_name = models.CharField(max_length=15)
last_name = models.CharField(max_length=15)
mobile = models.IntegerField(unique=True)
date_joined = models.DateTimeField(default=timezone.now)
is_active = models.BooleanField(default=True)
is_admin = models.BooleanField(default=False)
objects = UserManager()
USERNAME_FIELD = 'email'
REQUIRED_FIELDS = ['first_name', 'last_name', 'mobile']
Бэкэнд аутентификации:
class EmailOrMobileAuthBackend(object):
def authenticate(self, username=None, password=None):
try:
user = get_user_model().objects.get(email=username)
if user.check_password(password):
return user
except User.DoesNotExist:
if username.isdigit():
try:
user = get_user_model().objects.get(mobile=username)
if user.check_password(password):
return user
except User.DoesNotExist:
return None
else:
return None
def get_user(self, user_id):
try:
return get_user_model().objects.get(pk=user_id)
except User.DoesNotExist:
return None
И добавили в settings.py:
AUTHENTICATION_BACKENDS = ('accounts.email_mobile_auth_backend.EmailOrMobileAuthBackend',)
Несмотря на то, что для входа на сайт администратора django, адрес электронной почты и номер мобильного телефона отлично работают при аутентификации пользователя. Однако, когда я пытаюсь получить токен для пользователя, использующего django rest framework JWT, я получаю сообщение об ошибке:
curl -X POST -d "email=admin@gmail.com&password=123123" http://localhost/api-token-auth/
"non_field_errors": [
"Unable to log in with provided credentials."
]
Я также добавил пользовательский базовый класс auth в среду проверки подлинности по умолчанию для Rest, но он все еще не работает:
REST_FRAMEWORK = {
...
'DEFAULT_AUTHENTICATION_CLASSES': (
'accounts.email_mobile_auth_backend.EmailOrMobileAuthBackend',
'rest_framework_jwt.authentication.JSONWebTokenAuthentication',
),
}
Что мне не хватает? Почему он работает при входе на сайт администратора django, но выдает ошибку при получении токена с django rest framework jwt?
Обновить
Я сделал еще один auth backend в соответствии с рекомендациями и добавил его в DEFAULT_AUTHENTICATION_CLASSES
, но даже это не работает.
class DrfAuthBackend(BaseAuthentication):
def authenticate(self, username=None, password=None):
try:
user = get_user_model().objects.get(email=username)
if user.check_password(password):
return user, None
except User.DoesNotExist:
if username.isdigit():
try:
user = get_user_model().objects.get(mobile=username)
if user.check_password(password):
return user, None
except User.DoesNotExist:
return None
else:
return None
Настройки:
REST_FRAMEWORK = {
'DEFAULT_PERMISSION_CLASSES': (
'rest_framework.permissions.IsAdminUser',
),
'DEFAULT_AUTHENTICATION_CLASSES': (
'accounts.email_mobile_auth_backend.EmailOrMobileAuthBackend',
'accounts.email_mobile_auth_backend.DrfAuthBackend',
'rest_framework_jwt.authentication.JSONWebTokenAuthentication',
),
}
Обновить
Изменение args
в классе аутентификации из username
в email
кажется, работает для получения auth_token
но опять же не работает войти на сайт администратора.
class EmailOrMobileAuthBackend(object):
def authenticate(self, email=None, password=None):
try:
user = get_user_model().objects.get(email=email)
if user.check_password(password):
return user
except User.DoesNotExist:
if email.isdigit():
try:
user = get_user_model().objects.get(mobile=email)
if user.check_password(password):
return user
except User.DoesNotExist:
return None
else:
return None
def get_user(self, user_id):
try:
return get_user_model().objects.get(pk=user_id)
except User.DoesNotExist:
return None
2 ответа
Вы должны проверить документацию DRF для пользовательских бэкэндов аутентификации.
Я думаю, что ваш пользовательский бэкэнд аутентификации ломает его, вы можете решить его, удалив свой из настроек DRF:
REST_FRAMEWORK = {
...
'DEFAULT_AUTHENTICATION_CLASSES': (
'rest_framework_jwt.authentication.JSONWebTokenAuthentication',
),
}
Или исправив ваш, который в принципе не такой, как для пользовательской аутентификации Django, как вы должны расширить authentication.BaseAuthentication
и он возвращает кортеж.
from rest_framework import authentication
class DrfAuthBackend(authentication.BaseAuthentication):
def authenticate(self, email=None, password=None):
try:
user = get_user_model().objects.get(email=email)
if user.check_password(password):
return user, None
except User.DoesNotExist:
if email.isdigit():
try:
user = get_user_model().objects.get(mobile=email)
if user.check_password(password):
return user, None
except User.DoesNotExist:
return None
else:
return None
Затем используйте это в настройках DRF:
REST_FRAMEWORK = {
'DEFAULT_PERMISSION_CLASSES': (
'rest_framework.permissions.IsAdminUser',
),
'DEFAULT_AUTHENTICATION_CLASSES': (
'accounts.email_mobile_auth_backend.DrfAuthBackend',
'rest_framework_jwt.authentication.JSONWebTokenAuthentication',
),
}
Для входа в Django:
class EmailOrMobileAuthBackend(object):
def authenticate(self, username=None, password=None):
try:
user = get_user_model().objects.get(email=username)
if user.check_password(password):
return user
except User.DoesNotExist:
if username.isdigit():
try:
user = get_user_model().objects.get(mobile=username)
if user.check_password(password):
return user
except User.DoesNotExist:
return None
else:
return None
def get_user(self, user_id):
try:
return get_user_model().objects.get(pk=user_id)
except User.DoesNotExist:
return None
Тогда для настроек:
AUTHENTICATION_BACKENDS = ('accounts.email_mobile_auth_backend.EmailOrMobileAuthBackend',)
В файле settings.py добавьте следующее:
AUTH_USER_MODEL = 'accounts.email_mobile_auth_backend.EmailOrMobileAuthBackend'