dunmaksim
@dunmaksim
Технический писатель

Django authenticate() всегда возвращает None, а SO не даёт ответа на вопрос. Что делать?

Здравствуйте!

Сегодня обнаружил неприятную вещь - самописный модуль авторизации сломался. Если раньше работал вот этот код, то теперь - нет:

class LoginView(AuthView, GenericAPIView):

    """
    Вид предназначен для простой аутентификации
    """

    def post(self, request, *args, **kwargs):
        data = request.data

        username = data.get('username', None)
        email = data.get('email', None)
        password = data.get('password', None)

        if username is None:
            username = email

        account = authenticate(username=username, password=password)

        if account is None:
            raise Exception("Не удалось авторизоваться")

        if account is not None:
            if account.is_active:
                login(request, account)
                return Response(status=status.HTTP_200_OK)
            else:
                return Response({
                    'status': 'Unauthorized',
                    'message': 'This account has been disabled.'
                }, status=status.HTTP_401_UNAUTHORIZED)
        else:
            return Response({
                'status': 'Unauthorized',
                'message': 'Имя пользователя или пароль указаны неверно.'
            }, status=status.HTTP_401_UNAUTHORIZED)


Функция authenticate() всегда выдаёт None, даже при аутентификации в Django shell. Куда копать? В чём причина? CSRF-токены передаю, логины и пароли верные, задавал через set_password() и всё такое. Не могу авторизоваться, хотя ещё вчера всё работало.
В settings.py:

AUTH_USER_MODEL = 'extuser.User'

AUTHENTICATION_BACKENDS = (
    "django.contrib.auth.backends.ModelBackend",
)

MIDDLEWARE_CLASSES = (
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.common.CommonMiddleware',
    'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.auth.middleware.SessionAuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    'django.middleware.clickjacking.XFrameOptionsMiddleware',
    'django.middleware.locale.LocaleMiddleware',
)
  • Вопрос задан
  • 1400 просмотров
Решения вопроса 2
crazyzubr
@crazyzubr
Python backend-developer
Для отладки вместо стандартной функции authenticate пропишите копию выше вьюхи, например:

def authenticate(username=None, password=None, **kwargs):
        from django.contrib.auth import get_user_model
        UserModel = get_user_model()
        if username is None:
            username = kwargs.get(UserModel.USERNAME_FIELD)
        try:
            user = UserModel._default_manager.get_by_natural_key(username)
            if user.check_password(password):
                return user
        except UserModel.DoesNotExist:
            # Run the default password hasher once to reduce the timing
            # difference between an existing and a non-existing user (#20760).
            UserModel().set_password(password)


После чего можно отследить в каком месте происходит затык. UserModel.DoesNotExist или не проходит user.check_password(password). Это также можно сделать через IDE в debug режиме, без копирования кода.

Можно предположить, что менялась модель юзера, а миграции проведены не были.
Ответ написан
Комментировать
un1t
@un1t
После set_password еще как минимум save надо сделать. Через админку поменяй парлоь, чтобы точно быть уверенным, что он верный.

Ну и вот этот кусок выглядит странно,
if username is None:
    username = email

авторизация же по username идет, а если ты тут email подставляешь

Такой код позволяет отправить пост запрос в котором нет указанных полей и ты об это не узнаешь.
username = data.get('username', None)
email = data.get('email', None)
password = data.get('password', None)

Хотя бы для теста ассерты вставь. Может верстальщик там намутил че, поля переименовал.
Ответ написан
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы