Покрытие изображения Франк на Бессмысленно
В Предыдущая часть Мы создали пользовательскую модель пользователей в 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”