1

我有一个简单的聊天,我使用频道 2。在用户连接到消费者之前,我在通过令牌 JWT(简单 JWT)授权时遇到问题。

我的中间件:

from channels.auth import AuthMiddlewareStack
from rest_framework.authtoken.models import Token
from django.contrib.auth.models import AnonymousUser


class TokenAuthMiddleware:
    """
    Token authorization middleware for Django Channels 2
    """

    def __init__(self, inner):
        self.inner = inner

    def __call__(self, scope):
        headers = dict(scope['headers'])
        if b'authorization' in headers:
            try:
                token_name, token_key = headers[b'authorization'].decode().split()
                if token_name == 'Token':
                    token = Token.objects.get(key=token_key)
                    scope['user'] = token.user
            except Token.DoesNotExist:
                scope['user'] = AnonymousUser()
        return self.inner(scope)

TokenAuthMiddlewareStack = lambda inner: TokenAuthMiddleware(AuthMiddlewareStack(inner))

我的消费者的片段:

User = get_user_model()


class ChatConsumer(WebsocketConsumer):

    def connect(self):
        """
        Join channel group by chatname.
        """
        self.group_name = 'chat_{0}'.format(self.scope['url_route']['kwargs']['chatname'])

        if self.scope['user'] == AnonymousUser():
            raise DenyConnection("Invalid User")

        async_to_sync(self.channel_layer.group_add)(
            self.group_name,
            self.channel_name,
        )

        self.accept()

    def disconnect(self, close_code):
        """
        Leave channel by group name.
        """
        async_to_sync(self.channel_layer.group_discard)(
            self.group_name,
            self.channel_name
        )

我的路由:

from .auth import TokenAuthMiddlewareStack

application = ProtocolTypeRouter({
    'websocket': TokenAuthMiddlewareStack(
        URLRouter([
            path('ws/chat/<slug:chatname>/', ChatConsumer),
        ])
    ),
})

现在有两个问题。

如何在我的测试客户端 Web 套接字中传递令牌?上面的片段是正确的吗?因为我从客户那里收到

    raise InvalidStatusCode(status_code)
websockets.exceptions.InvalidStatusCode: server rejected WebSocket connection: HTTP 403

我的测试客户:

from asgiref.sync import async_to_sync
import websockets
import asyncio
import json
test_json = "some test to send via socket"
def test_url2(url):
    async def inner():
        async with websockets.connect(url) as websocket:
            await websocket.send(test_json)
            print(test_json)
    return asyncio.get_event_loop().run_until_complete(inner())

test_url2("ws://0.0.0.0:8080/ws/over/3ff621b1-b392-4a82-ab35-a0ad81ab1179_f99c82ba-1404-442c-ba08-653f84d58aa4")

谢谢您的回复

4

1 回答 1

0

我找不到这样做的方法,作为一种解决方法,我从请求对象访问了用户。设置将为您提供请求对象的中间件:

#get_request.py
from threading import current_thread

from django.utils.deprecation import MiddlewareMixin


_requests = {}


def current_request():
    return _requests.get(current_thread().ident, None)


class RequestMiddleware(MiddlewareMixin):

    def process_request(self, request):
        _requests[current_thread().ident] = request

    def process_response(self, request, response):
        # when response is ready, request should be flushed
        _requests.pop(current_thread().ident, None)
        return response

    def process_exception(self, request, exception):
        # if an exception has happened, request should be flushed too
        _requests.pop(current_thread().ident, None)

在你的 settings.py 中添加到现有的 MIDDLEWARE 列表中:

MIDDLEWARE = [
   ... 
    'users.get_request.RequestMiddleware',
   ...
]

最后得到用户:(在你的consumers.py或任何地方)

from users.get_request import current_request

class ChatConsumer(AsyncWebsocketConsumer):
    async def connect(self):
        self.user = current_request().user
于 2020-11-16T13:24:27.563 回答