У меня есть приложение WSGI, к которому я добавляю Django Каналы, чтобы обеспечить функциональность веб-сокета. Я создал потребителя с помощью WebsocketConsumer, добавил пользовательское промежуточное ПО в файл маршрутизации и реализовал базовую c версию извлечения токена из входящего запроса на подключение. Я могу успешно распечатать токен, который находится в базе данных, поэтому я знаю, что передается правильная информация.
Я могу подключиться к сокету, но он всегда возвращается как анонимный пользователь в области действия. Похоже, что функция get_user_from_token
не получает возможности выполнить до того, как выполнится функция соединения, потому что все отпечатки в функции __call__
класса TokenAuthMiddleware печатаются, и ни один из отпечатков из get_user_from_Token не печатается. Я попытался переключить потребителя на асин c, но это открыло целый ряд других проблем, которые я не мог понять. Я попытался поместить async
перед __call__
и await
перед вызовом функции, но это тоже не сработало. Текущая ошибка, которую я получаю:
Exception inside application: 'coroutine' object has no attribute '_wrapped'
File "C:\Users\PC\Envs\p3\lib\site-packages\channels\sessions.py", line 183, in __call__
return await self.inner(receive, self.send)
File "C:\Users\PC\Envs\p3\lib\site-packages\channels\middleware.py", line 40, in coroutine_
call
await self.resolve_scope(scope)
File "C:\Users\PC\Envs\p3\lib\site-packages\channels\auth.py", line 166, in resolve_scope
scope["user"]._wrapped = await get_user(scope)
'coroutine' object has no attribute '_wrapped'
Как мне получить промежуточное ПО до fini sh, что он делает до того, как connect
попытается проверить пользователя?
my_app / routing.py
from channels.routing import ProtocolTypeRouter, URLRouter
import api.channels.routing
from my_app.ws_token_auth import TokenAuthMiddlewareStack
application = ProtocolTypeRouter({
# (http->django views is added by default)
'websocket': TokenAuthMiddlewareStack(
URLRouter(
api.channels.routing.websocket_urlpatterns
)
),
})
API / каналы / consumer.py
import json
from asgiref.sync import async_to_sync
from channels.db import database_sync_to_async
from channels.generic.websocket import WebsocketConsumer
class HeaderConsumer(WebsocketConsumer):
def connect(self):
if self.scope["user"].is_anonymous:
# Reject the connection
print('rejected')
self.close()
else:
self.accept()
self.user = self.scope['user']
self.message_threads = set()
def disconnect(self, code):
"""
Called when the WebSocket closes for any reason.
"""
# Leave all the rooms we are still in
for thread_id in list(self.message_threads):
try:
self.leave_thread(thread_id)
except ClientError:
pass
def receive(self, text_data):
text_data_json = json.loads(text_data)
message = text_data_json['message']
self.send(text_data=json.dumps({
'message': message + message
}))
my_app / ws_token_auth.py
from channels.auth import AuthMiddlewareStack
from channels.db import database_sync_to_async
from rest_framework.authtoken.models import Token
from django.contrib.auth.models import AnonymousUser
from django.db import close_old_connections
@database_sync_to_async
def close_connections():
close_old_connections()
@database_sync_to_async
def get_user_from_token(t):
try:
print("trying token" + t)
token = Token.objects.get(token=t).prefetch_related('user')
return token.user
except Token.DoesNotExist:
print("failed")
return AnonymousUser()
class TokenAuthMiddleware:
"""
Token authorization middleware for Django Channels 2
"""
def __init__(self, inner):
self.inner = inner
def __call__(self, scope):
close_connections()
print("hi")
headers = dict(scope['headers'])
if b'cookie' in headers:
pieces = headers[b'cookie'].decode().split("; ")
key_values = {i.split('=', 1)[0]: i.split('=', 1)[1] for i in pieces}
print("x")
if 'token' in key_values:
try:
scope['token'] = key_values['token']
print("y")
user = get_user_from_token(key_values['token'])
print("z")
except Token.DoesNotExist:
print("no token")
user = AnonymousUser()
else:
print("no token?")
else:
print("no cookie")
return self.inner(dict(scope, user=user))
TokenAuthMiddlewareStack = lambda inner: TokenAuthMiddleware(AuthMiddlewareStack(inner))