Рубрики
Без рубрики

Пользовательская аутентификация пользователя в Django, с тестами

Понять, как работает аутентификация и как настроить его. Теги с Python, Django, учебником.

Покрытие изображения Франк на Бессмысленно

В Предыдущая часть Мы создали пользовательскую модель пользователей в Django. В этой части я хотел бы показать, как катить пользовательскую аутентификацию. Ни настраиваемые пользовательские модели, ни пользовательские аутентификации не требуются для контроля доступа на основе ролей, но я хотел бы, чтобы эта серия была полной экскурсией по аутентификации и разрешению в Джангу. Код, сопровождающий серии, можно найти в Github Отказ Так что давайте начнем!

Аутентификация Django 101.

Аутентификация – это процесс выяснения, кто утверждает, что пользователь должен быть и проверки претензии. В системе аутентификации Django «низкий уровень» подход к проверке идентификации пользователя – звонить аутентифицировать от django.contrib.auth.authenticate . Эта функция проверяет идентификацию пользователя на каждом Аутентификация Backend настроен в Аутентификация_backends Переменная settings.py Отказ

По умолчанию Django использует Modelbackend. как единственная бэкэнда аутентификации. Поучительно изучить реализацию Modelbackend в Github :

class ModelBackend(BaseBackend):
    def authenticate(self, request, username=None, password=None, **kwargs):
        if username is None:
            username = kwargs.get(UserModel.USERNAME_FIELD)
        if username is None or password is None:
            return
        try:
            user = UserModel._default_manager.get_by_natural_key(username)
        except UserModel.DoesNotExist:
            # Run the default password hasher once to reduce the timing
            # difference between an existing and a nonexistent user (#20760).
            UserModel().set_password(password)
        else:
            if user.check_password(password) and self.user_can_authenticate(user):
                return user
    ...

Modelbackend Получает соответствующий пользователь от бэкэнда, используя либо данный имя пользователя или Username_field Определяется в пользовательской модели. Затем бэкэнда проверяет пароль, а также проверяет, может ли пользователь аутентифицироваться (проверяет, есть ли у пользователя IS_ Active Установлено на True ). Довольно просто, а?

Как мы будем аутентифицировать наших пользователей своим именем пользователя (E-mail) и паролем в этой серии, мы могли бы использовать Modelbackend Отказ Тем не менее, это поучительно написать нашу собственную бэкэнду. Кроме того, мы избавимся от всей ненужной котельной в Modelbackend Исходя из системы разрешения по умолчанию Django, которая нам не понадобится.

Пользовательская бэкэнда аутентификации

Каждая бэкэнда аутентификации в Джангу должна иметь методы аутентифицировать () и get_user () Отказ аутентифицировать () Метод должен проверить учетные данные, которые он получает и возвращает пользовательский объект, который соответствует этим учетным данным, если учетные данные действительны. Если учетные данные недействительны, это должно вернуть Нет Отказ

Вот простая реализация CheckPasswordbackend. :

# rbac/core/auth.py
import typing

from rbac.core.models import User
from rbac.core import services


class CheckPasswordBackend:
    def authenticate(
        self, request=None, email=None, password=None
    ) -> typing.Optional[User]:
        user = services.find_user_by_email(email=email)

        if user is None:
            return None

        return user if user.check_password(password) else None

    def get_user(self, user_id) -> typing.Optional[User]:
        try:
            return User.objects.get(id=user_id)
        except User.DoesNotExist:
            return None

Мы используем services.find_user_by_email Способ создан в предыдущем посте для получения пользователя по электронной почте. Если пароль совпадает, мы возвращаем соответствующего пользователя. Вот и все! Давайте установим Django, чтобы использовать эту бэкэнду для аутентификации:

# rbac/settings.py
AUTHENTICATION_BACKENDS = ["rbac.core.auth.CheckPasswordBackend"]

Теперь, когда мы называем аутентифицировать от django.contrib.auth мы по сути, называем аутентифицировать () от CheckPasswordBackend Отказ

Почему мы также определяли get_user выше в CheckPasswordBackend ? Это очень хороший вопрос. Ответ заключается в том, что документация Django говорит, что она должна быть реализована, но я понятия не имею, почему. Пожалуйста, бросьте комментарий, если вы знаете!

Итак, теперь у нас есть отличная новая бэкэнда аутентификации, как мы на самом деле используем его? Мы пишем вид AUTH/LOCK Это позволяет пользователям войти в систему с их электронной почтой и паролем. Если идентификация пользователя проверена, мы входим в систему, вызов Войти () Отказ Это создает сеанс для пользователя и хранит SessionId В файле cookie, позволяющее пользователю выполнять аутентифицированные запросы.

Перед реализацией Вход Вид, давайте будем ответственными разработчиками и писать тесты.

Тесты

Чтобы проверить логин, нам нужно создать пример пользователя. Мы делаем это в pteest Приспособление:

# tests/test_views.py
import pytest

from rbac.core.services import create_user

TEST_USER_NAME = "Jane Doe"
TEST_USER_EMAIL = "jane@example.org"
TEST_USER_PASSWORD = "aösdkfjgösdgäs"


@pytest.fixture
def sample_user():
    user = create_user(
        name=TEST_USER_NAME, email=TEST_USER_EMAIL, password=TEST_USER_PASSWORD
    )
    return user

Теперь давайте будем использовать этот приспособлений в два теста. Первый тест проверяет, что вход с неверным возвратом пароля 401:

from django.test import Client

@pytest.mark.django_db
def test_login_fails_with_invalid_credentials(sample_user):
    client = Client()
    response = client.post(
        "/auth/login",
        dict(email=TEST_USER_EMAIL, password="wrong-password"),
        content_type="application/json",
    )
    assert response.status_code == 401
    assert "sessionid" not in client.cookies

Мы используем Django Test Client Для создания запросов от тестов без фактического запуска сервера.

Второй тест проверяет, что логин преуспевает с действительными учетными данными:

@pytest.mark.django_db
def test_login_succeeds_with_valid_credentials(sample_user):
    client = Client()
    assert "sessionid" not in client.cookies
    response = client.post(
        "/auth/login",
        dict(email=TEST_USER_EMAIL, password=TEST_USER_PASSWORD),
        content_type="application/json",
    )
    assert response.status_code == 200
    assert "sessionid" in client.cookies

На данный момент мы можем начать Pтобы-часы С помощью команды PTW - Тесты/test_views.py и код до прохода испытаний. Если вы еще не добавили Pтобы-часы к требования - dev.txt Тем не менее, вы должны сделать это сейчас.

Вход в систему

Давайте теперь добавим представление для входа в систему пользователя. Мы ожидаем, что пользователи публикуют их электронную почту и пароль в корпусе запроса JSON. Вот как мы разбираем тело, аутентифицируйте пользователя и входите в систему:

# rbac/core/auth.py
import json

from django.contrib.auth import authenticate, login
from django.http import HttpResponse
from django.views.decorators.http import require_http_methods

@require_http_methods(["POST"])
def login_view(request):
    body = json.loads(request.body.decode())
    user = authenticate(request, email=body["email"], password=body["password"])

    if user:
        login(request, user)
        return HttpResponse("OK")
    else:
        return HttpResponse("Unauthorized", status=401)

Если звонок на аутентифицировать Возвращает действительный пользователь, войти в систему пользователя, создать сеанс и установить файл cookie сеанса. В противном случае мы возвращаем 401.

Теперь нам нужно определить конечную точку для нашего мнения:

# rbac/core/auth.py
from django.urls.conf import re_path

urlpatterns = [
    re_path("^login$", login_view),
]

Нам также нужно определить новый маршрут с именем auth в RBAC/URLS.PY. :

# rbac/core/urls.py

from django.conf.urls import include, re_path
from rbac.core import views

urlpatterns = [
    re_path(r"^$", views.index),
    re_path(r"^auth/", include("rbac.core.auth")),
]

Со всеми это сделано, ваши тесты должны проходить с летающими цветами.

Поздравляем, теперь вы должны иметь гораздо более глубокое понимание того, как работает аутентификация в Джангу! Пожалуйста, оставьте комментарий Как вам понравилась статья. В следующих частях мы будем работать в направлении контроля доступа на основе ролей. Увидимся в следующий раз!

Оригинал: “https://dev.to/ksaaskil/custom-user-authentication-in-django-with-tests-34em”