Django Channels Аутентификация
https://channels.readthedocs.io/en/latest/topics/authentication.html#authentication
Channels поддерживают нестандартную аутентификацию Django для потребителей HTTP и WebSocket, и вы можете написать собственное промежуточное программное обеспечение или код обработки, если хотите поддерживать другую схему аутентификации (например, токены в URL-адресе).
Django аутентификация
AuthMiddleware в
channels поддерживает стандартную аутентификацию Django, где данные пользователя сохраняются в сеансе. Он разрешает доступ только для чтения к пользовательскому объекту в scope
.
AuthMiddleware
требует SessionMiddleware
для работы, что само по себе требует CookieMiddleware
. Для удобства они также представлены как комбинированный вызываемый объект, AuthMiddlewareStack
который включает в себя все три.
Чтобы использовать промежуточное ПО, оберните его вокруг соответствующего уровня потребителя (consumer) в asgi.py
:
from django.urls import re_path from channels.routing import ProtocolTypeRouter, URLRouter from channels.auth import AuthMiddlewareStack from myapp import consumers application = ProtocolTypeRouter({ "websocket": AuthMiddlewareStack( URLRouter([ re_path(r"^front(end)/quot;, consumers.AsyncChatConsumer.as_asgi()), ]) ), })
Хотя вы можете обернуть промежуточное ПО вокруг каждого потребителя индивидуально, рекомендуется обернуть его вокруг компонента приложения более высокого уровня, например, в этом случае URLRouter
.
Обратите внимание, что AuthMiddleware
будет работать только с протоколами, которые предоставляют заголовки HTTP в своих scope (объёмы, рамки, сферы действия)
- по умолчанию это HTTP и WebSocket.
Чтобы получить доступ к пользователю, просто используйте self.scope["user"]
в своем потребительском коде:
class ChatConsumer(WebsocketConsumer): def connect(self, event): self.user = self.scope["user"]
Пользовательская аутентификация
Если у вас есть настраиваемая схема аутентификации, вы можете написать настраиваемое ПО промежуточного слоя для анализа деталей и помещения объекта пользователя (или любого другого объекта, который вам нужен) в вашу область видимости.
Промежуточное ПО написано как вызываемый объект, который принимает приложение ASGI и обертывает его для возврата другого приложения ASGI. Большую часть аутентификации можно просто выполнить в области видимости, поэтому все, что вам нужно сделать, это переопределить начальный конструктор, который принимает область видимости, а не сопрограмму, запускающую событие.
Вот простой пример промежуточного программного обеспечения, которое просто берет идентификатор пользователя из строки запроса и использует его:
from channels.db import database_sync_to_async @database_sync_to_async def get_user(user_id): try: return User.objects.get(id=user_id) except User.DoesNotExist: return AnonymousUser() class QueryAuthMiddleware: """ Пользовательское промежуточное ПО (небезопасное), которое берет идентификаторы пользователей из строки запроса. """ def __init__(self, app): # Store the ASGI application we were passed self.app = app async def __call__(self, scope, receive, send): # Найдите пользователя в строке запроса (вы также должны сделать # такие вещи, как проверка, является ли он действительным # идентификатором пользователя или уже заполнена # область ["пользователь"]). scope['user'] = await get_user(int(scope["query_string"])) return await self.app(scope, receive, send)
Те же принципы могут применяться для аутентификации по протоколам, отличным от HTTP; например, вы можете захотеть использовать чье-то имя пользователя чата из протокола чата, чтобы превратить его в пользователя.
Как выполнить вход / выход пользователя
Каналы предоставляют функции прямого входа и выхода (как и contrib.auth
пакет Django ), такие как channels.auth.login
и channels.auth.logout
.
В пределах вашего потребителя вы можете дождаться await login(scope, user, backend=None)
входа пользователя в систему. Для этого необходимо, чтобы в вашей области был объект session; лучший способ сделать это - убедиться, что ваш потребитель заключен в sessionSessionMiddlewareStack или в AuthMiddlewareStack
Вы можете выйти из системы с помощью logout(scope)
функции async.
Если вы находитесь в WebSocket потребителя или входите в систему после того, как первый ответ был отправлен потребителю http, сеанс заполняется, но не сохраняется автоматически - вы должны вызвать scope["session"].save()
после логина в свой код потребителя:
from channels.auth import login class ChatConsumer(AsyncWebsocketConsumer): ... async def receive(self, text_data): ... # вход пользователя в эту сессию. await login(self.scope, user) # сохранить сеанс (если серверная часть сеанса не имеет доступа к базе данных, вы можете использовать `sync_to_async`) await database_sync_to_async(self.scope["session"].save)()
При вызове login(scope, user)
, logout(scope)
или get_user(scope)
от синхронной функции вам нужно будет обернуть их в async_to_sync
, так как мы предоставляем только асинхронной версии:
from asgiref.sync import async_to_sync from channels.auth import login class SyncChatConsumer(WebsocketConsumer): ... def receive(self, text_data): ... async_to_sync(login)(self.scope, user) self.scope["session"].save()
Примечание
Если вы используете долго работающий потребитель, веб-сокет или HTTP с длительным опросом, возможно, что пользователь выйдет из своего сеанса в другом месте во время работы вашего потребителя. Вы можете периодически использовать, get_user(scope)
чтобы быть уверенным, что пользователь все еще залогинен в системе.