Почему в Django check_password=True, а authenticate=None

Я пытаюсь написать модульный тест для конечной точки входа в Django, используя как можно больше встроенной функциональности.

Существуют тесты, подтверждающие, что конечная точка создания учетной записи работает правильно.

В представлении входа в систему, однако, функция check_password() вернет True для этого теста, но функция authenticate() вернет None.

Безопасно ли вместо этого использовать функцию check_password()?

Иначе, как мне обновить этот код, чтобы использовать функцию authenticate()?

accounts.py

class Account(AbstractUser):
    username = models.CharField(max_length=150, unique=True, null=False, default='')
    password = models.CharField(max_length=100)
    ...

    REQUIRED_FIELDS = ['username', 'password']

    class Meta:
        app_label = 'accounts'
        db_table = 'accounts_account'

    objects = models.Manager()

test_login.py

def test_login(self):
    # Create account
    request_create = self.factory.post('/accounts/account',
                                       self.request_data,
                                       content_type='application/json')
    view = AccountView.as_view()
    response_create = view(request_create)

    # Login account
    request_login = self.factory.post('/accounts/login',
                                      self.request_data,
                                      content_type='application/json')

    view = LoginView.as_view()
    response = view(request_login)

views.py

class LoginView(View):

    def post(self, request):
        r = json.loads(request.body)
        username = r.get('username')
        password = r.get('password')
        cp = check_password(password, Account.objects.get(username=username).password)
        user = authenticate(username=username, password=password)

P.S. Я проверил этот поток и is_active установлен в true.

Это безопасно. Основное различие заключается в том, что при использовании check_password() вы вручную проверяете пользователя из бэкенда аутентификации, поэтому вы должны получить объект пользователя и сравнить его пароль с открытым текстом, как это делается в:

check_password(password, Account.objects.get(username=username).password)

В то время как с помощью authenticate() можно проверить учетные данные на нескольких бэкендах аутентификации. Это означает, что в первом случае вы не сможете подключить ваше приложение к другим источникам аутентификации

Вам не хватает некоторого кода в tests.py и views.py. Тем не менее, вот полный тест этого LoginView:

tests.py

class TestClientLogin(TestCase):

    def setUp(self):
        User = get_user_model()
        self.factory = RequestFactory()
        self.user = User.objects.create_user(
            username='test_user',
            email='test_user@example.com',
            password='super_secret'
        )

    
    def test_user_login(self):
        request_data = {'username': 'test_user', 'password': 'super_secret'}
        request = self.factory.post(
            '/accounts/login/', 
            request_data , 
            content_type='application/json'
        )

        response = LoginView.as_view()(request)
        data = json.loads(response.content)

        self.assertEqual(self.user.username, data['username'])
        self.assertEqual(response.status_code, 200)

views.py

class LoginView(View):

    def post(self, request):
        data = json.loads(request.body)
        username = data.get('username')
        password = data.get('password')

        user = authenticate(username=username, password=password)

        if user is not None:
            return JsonResponse({'username': user.username})
        else:
             return JsonResponse({'username': None})

Если вы хотите использовать как можно больше встроенной функциональности , :

settings.py:

AUTH_USER_MODEL = 'accounts.Account'

accounts/models.py:

class Account(AbstractUser):
    # you dont need to define username or password again
    ...

    REQUIRED_FIELDS = ['username', 'password']

    class Meta:
        # you don't need to define default app_label, db_table

     objects = UserManager()  # otherwise don't work "python manage.py createsuperuser"

accounts/views.py:

from django.contrib.auth.views import LoginView


class ClientLogin(LoginView):
    pass

accounts/tests.py:

from django.test import TestCase, Client
from django.utils.crypto import get_random_string

class TestClientLogin(TestCase):

    def setUp(self):
        User = get_user_model()
        self.username, self.password = get_random_string(20), get_random_string(20)  # don't use constants in tests
        self.user = User.objects.create_user(username=self.username, password=self.password )

    def test_user_login(self):
        request_data = {'username': self.username, 'password': self.password}
        response = Client().post('/accounts/login/', request_data)
        self.assertEqual(response.status_code, 302)

BUT:

вам не нужно тестировать ClientLogin, у вас нет кода в view.

Вернуться на верх