Аутентификация токена в каналах Django и веб-сокетах
Предварительные требования: Django, WebSockets, каналы Django, аутентификация по токену.
Самые популярные темы Django сейчас — это WebSockets и каналы Django, потому что они позволяют быстро и легко общаться, работая в режиме реального времени без постоянного обновления страницы. При работе только с механизмом шаблонов Django, а не с инфраструктурой REST, метод аутентификации, который используют каналы Django, — это аутентификация сеанса. Пользователь, который в данный момент вошел в систему, также отображается в системе аутентификации каналов Django.
// This is not possible in websockets .
var socket = new WebSocket(“path_of_the_socket” , headers = { “Authorization’: “token token_string” })
Что ж, использование веб-аутентификации — это один из способов достижения вашей цели. Возврат файла cookie на веб-сайт позволяет вам еще раз подключиться к серверу WebSocket с файлом cookie, пройти аутентификацию и затем продолжить. Однако аутентификация на основе файлов cookie может быть крайне ненадежной и иметь различные проблемы. Поэтому, чтобы решить эту проблему, мы можем передать токен аутентификации из параметров запроса сокета, а затем создать новый стек аутентификации, который будет располагаться поверх существующих при маршрутизации соединений WebSocket.
Однако работа с остальным фреймворком с аутентификацией по токену или аутентификацией JWT непроста для веб-сокетов и каналов; в результате может быть сложно войти в систему пользователя через каналы и сокеты при использовании аутентификации с помощью токена или остальной инфраструктуры. Вы не можете отправить токены аутентификации/JWT в заголовки WebSocket, как в простом сообщении, или получить запрос в заголовке авторизации.
Примечание. Этот процесс является полностью асинхронным, поскольку веб-сокеты и каналы работают с ASGI (асинхронный интерфейс шлюза сервера).
Настройка нашего проекта
Структура файла
Это файловая структура после выполнения всех шагов, описанных в этой статье.
Шаг 1: Создайте виртуальную среду и активируйте ее.
Шаг 2: Установите Django и запустите свой проект.
Шаг 3. Создайте проект с именем TokenAuth.
django-adminb startproject TokenAuth
Шаг 4: Запустите приложение с именем token_auth_app, перейдя в папку проекта.
cd TokenAuth python manage.py startapp token_auth_app
Шаг 5: Добавьте свое приложение в список установленных приложений в settings.py.
"token_auth_app.apps.TokenAuthAppConfig"
Шаг 6: Настроить каналы Django для серверной части. Установить Django-каналы
python -m pip install -U channels
Шаг 7: Добавьте каналы в установленные приложения.
Python3
INSTALLED_APPS = [ "token_auth_app.apps.TokenAuthAppConfig" , "channels" ] |
Шаг 8. Для создания аутентификации по токену для серверных приложений требуется установка фреймворка REST. Для аутентификации токенов используется пакет токенов аутентификации остальной платформы, который содержит модель токена.
pip install django-rest-framework
Шаг 9: Установите корр.
pip install django-cors-headers
Шаг 10: Добавьте как в INSTALLED_APPS, так и в пакет аутентификации токена.
Python3
INSTALLED_APPS = [ "token_auth_app.apps.TokenAuthAppConfig" , ... "channels" , "rest_framework" , "rest_framework.authtoken" , "corsheaders" , ] |
Шаг 11: Установите для параметра ALLOWED_HOSTS значение *. Кроме того, добавьте промежуточное ПО cors в список MIDDLEWARE. Настройка cors выполняется таким образом, чтобы хост разрешал все источники, и мы могли взаимодействовать с серверным приложением.
Python3
ALLOWED_HOSTS = [ "*" ] CORS_ALLOW_ALL_ORIGINS = True MIDDLEWARE = [ "django.middleware.security.SecurityMiddleware" , "django.contrib.sessions.middleware.SessionMiddleware" , # ----------------------------------------- "corsheaders.middleware.CorsMiddleware" , # ----------------------------------------- "django.middleware.common.CommonMiddleware" , "django.middleware.csrf.CsrfViewMiddleware" , "django.contrib.auth.middleware.AuthenticationMiddleware" , "django.contrib.messages.middleware.MessageMiddleware" , "django.middleware.clickjacking.XFrameOptionsMiddleware" , ] |
Реализация кода
Настройка файлов по одному:
файл token_auth_app/consumers.py:
В папке приложения создайте Consumer.py, который будет обрабатывать все входящие команды приема и отправки из WebSocket.
Python3
from channels.generic.websocket import AsyncJsonWebsocketConsumer class TokenAuthConsumer(AsyncJsonWebsocketConsumer): async def connect( self ): await self .accept() print ( self .scope[ "user" ].username) print ( self .scope[ "user" ].email) async def disconnect( self , close_code): ... async def receive_json( self , message): command = message.get( "command" ) if command = = "Say hello !" : print (message[ "data_string" ]) await self .send_json({ "command_response" : "The command to say hello was recevied ", "data_string_bacK" : message.get ( "data_string" , None ) }) |
Объяснение кода:
Мы создали Consumer с именем класса TokenAuthConcumser, так как он использует события, отправленные и полученные приложением ASGI, создание которого мы увидим позже. Здесь мы наследуем AsyncJsonWebsocketConsumer , который является родительским классом-потребителем. В модуле AsyncJsonWebsocketConsumer у нас есть функции send_json и Receive_json, которые принимают JSON и отправляют JSON без дампа JSON.
- функция подключения: первая и основная функция, которая выполняется для установления соединения, — это та, которая принимает запрос WS на подключение, поэтому мы должны подключить его. Область действия — это словарь, который работает аналогично параметру запроса в функциональных представлениях (def fun(request)) в том смысле, что он содержит всю информацию о входящем соединении. доступ к пользователю осуществляется в виде области объекта dict["user"], которая предоставляет информацию о пользователе, который в данный момент вошел в систему. Затем извлекаются и отображаются имя пользователя и адрес электронной почты пользователя.
- функция отключения: принимает параметр close_code, а затем ничего не делает.
- Функция receive_json: мы должны реализовать метод получения в AsyncWebsocketConsumer. затем, чтобы получить элементы, мы должны загрузить данные (json.loads). Тем не менее, у вас есть прямой доступ к материалам здесь. Эта процедура использует сообщение, отправленное с внешнего интерфейса. Мы отправим эти данные, как указано ниже:
Javascript
{ "command" : "Say hello !" , "data_string" : "This is the data string !" , } |
По мере получения этих данных мы интерпретируем их и соответствующим образом отправляем ответы во внешнем интерфейсе.
файл token_auth_app/middlewares.py:
У него будет пользовательская аутентификация, которую мы создадим, и пользовательский стек будет наложен поверх всех стеков.
Python3
from rest_framework.authtoken.models import Token from urllib.parse import parse_qs from channels.db import database_sync_to_async from django.contrib.auth.models import AnonymousUser @database_sync_to_async def returnUser(token_string): try : user = Token.objects.get (key = token_string).user except : user = AnonymousUser() return user class TokenAuthMiddleWare: def __init__( self , app): self .app = app async def __call__( self , scope, receive, send): query_string = scope[ "query_string" ] query_params = query_string.decode() query_dict = parse_qs(query_params) token = query_dict[ "token" ][ 0 ] user = await returnUser(token) scope[ "user" ] = user return await self .app(scope, receive, send) |
Объяснение кода:
Использование различных модулей описано ниже:
- Токен: используется для проверки подлинности токена.
- parse_qs: используется для разбора параметров запроса из строки в словарь.
- database_sync_to_async: используется для извлечения данных из базы данных, поскольку Django ORM полностью синхронен.
- AnonymousUser: Это помогает, если мы не находим пользователя на основе токена, т.е. функция returnUser возвращает пользователя, связанного с токеном, переданным функции, иначе она возвращает AnonymousUser.
В функции __init__ мы определяем текущий экземпляр приложения для приложения, которое передается в стек. Затем асинхронная функция __call__() принимает три параметра: область приема и отправки. Область действия — это словарь, в котором есть все данные о соединении, как указано выше. send и receive — это команды для отправки и получения команд. Каждое приложение ASGI имеет три параметра: окружение, отправка и получение, здесь окружение — это переменная области видимости. query_string — это строка, переданная из предварительного запроса, например:
ws://localhost:8000/?token=fkdsahjkfshiadjkfhoasdfk"
Строка запроса, указанная в переменной строки запроса в области действия, имеет вид token=fkdsahjkfshiadjkfhoasdfk. Он отправляется в байтах в виде строки. Это указывает на то, что тип строки запроса — байты.
Строка байтов преобразуется в строку Python с помощью запроса string.decode(). p Parse qs(параметры запроса), с другой стороны, декодирует строку и добавляет ее в словарь Python. Диктовка представлена в виде пары ключ-значение. Поэтому мы получаем доступ к ключу токена, затем к первому элементу токена, token=qury_dict["token"][0], и, наконец, мы посещаем метод returnUser для получения пользователя. и мы устанавливаем его в свойство «user» области перед возвратом приложения.
Интересная часть этой переменной области видимости заключается в том, что вы можете полностью изменить ее и внести любые изменения, которые пожелаете. Это означает, что вы можете свободно изменять переменные в параметре области действия, а также добавлять новые.
для добавления просто добавьте как обычный словарь Python, т.е. scope["some_another_key"] = "value_for_the_key",
для удаления, del scope["some_key_that_exist"]
Файл TokenAuth/routing.py:
Он создаст приложение ASGI, которое будет обслуживаться и направлять все асинхронные URL-адреса WebSocket соответствующим потребителям.
Python3
from channels.routing import ProtocolTypeRouter, URLRouter from channels.security.websocket import AllowedHostsOriginValidator from django.urls import path from token_auth_app.consumers import TokenAuthConsumer from token_auth_app.middlewares import TokenAuthMiddleWare application = ProtocolTypeRouter( { "websocket" : TokenAuthMiddleWare( AllowedHostsOriginValidator( URLRouter( [path("", TokenAuthConsumer.as_asgi())] ) ) ) } ) |
Объяснение кода:
Использование различных модулей описано ниже:
- ProtocolTypeRouter : маршрутизирует сервер всего приложения в зависимости от типа протокола. Если используется протокол HTTP, он обслуживает приложение Django WSGI, а если WS — приложение ASGI.
- URLRouter : маршрутизирует маршруты подключения WS.
- AllowedHostsOriginValidator : этот стек безопасности используется для проверки соединения и принятия данных только с тех хостов, которые разрешены в файле settings.py приложения Django.
- path : Маршрутизация пути.
- TokenAuthConsumer : для обслуживания экземпляра потребителя для определенного соединения.
- TokenAuthMiddleware : для настройки экземпляра пользователя с использованием токена, переданного в соединение.
Затем установите стеки для обслуживания приложения ASGI в переменной приложения. Имейте в виду, что мы используем TokenAuthMiddleWare, и именно здесь мы можем установить пользователя с помощью токена. В приложении для аутентификации токенов middlewares.py мы недавно разработали этот класс.
Вы могли заметить, что мы не используем AuthMiddlewareStack. Это потому, что это полезно при обслуживании приложения ASGI из того же приложения или механизма шаблонов. Он хранит данные в сессиях.
Слои приложений и каналов ASGI в settings.py
Установите, что ваше приложение ASGI_APPLICATION будет обслуживать требуемых потребителей и маршрут. Принимая во внимание, что в CHANNEL_LAYERS мы используем InMemoryChannel, это для среды разработки.
Python3
WSGI_APPLICATION = "TokenAuth.wsgi.application" ASGI_APPLICATION = "TokenAuth.routing.application" CHANNEL_LAYERS = { "default" : { "BACKEND" : "channels.layers.InMemoryChannelLayer" , } } |
token_auth_app/signals.py
Этот файл создает объект токена для каждого пользователя, который будет создан, и этот signal.py будет импортирован файлом apps.py в готовой функции.
Python3
from django.dispatch import receiver from django.contrib.auth.models import User from django.db.models.signals import post_save from rest_framework.authtoken.models import Token @receiver (post_save, sender = User) def create_token(sender, instance, created, * * kwargs): if created: token = Token.objects.create(user = instance) token.save() |
token_auth_app/apps.py
Теперь, после настройки всей серверной части приложения и базы данных, это добавит в работу модель токенов, сеансы и остальную структуру.
Python3
from django.apps import AppConfig class TokenAuthAppConfig(AppConfig): default_auto_field = "django.db.models.BigAutoField" name = "token_auth_app" def ready( self ): import token_auth_app.signals |
token_auth_app/views.py
Здесь мы создадим страницу входа для внешней части, и оттуда мы сделаем почтовый запрос с именем пользователя и паролем, затем бэкэнд-представление проверит, есть ли пользователь там или нет, если пользователь там, то токен будет отправлен из бэкэнд в ответе, и оттуда мы создадим сокетное соединение. Для этого нам понадобится файл views.py, который будет обрабатывать вход в систему и отправлять токен.
Использование различных модулей описано ниже:
- Ответ : это объект ответа, который отправляется из представления API.
- api_view : преобразует обычное представление Django в представление API.
- аутентификация : это вернет пользователя на основе имени пользователя и пароля.