【问题标题】:Django DRF websocket channels 2 and authorize with token from Simple JWTDjango DRF websocket 通道 2 并使用来自 Simple JWT 的令牌进行授权
【发布时间】:2020-10-23 14:35:18
【问题描述】:

我有一个简单的聊天,我使用渠道 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 套接字中传递令牌? 上面的 sn-p 是正确的吗?因为我从客户那里收到

    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")

感谢回复

【问题讨论】:

    标签: websocket django-rest-framework jwt django-rest-framework-simplejwt


    【解决方案1】:

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

    #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
    

    【讨论】:

      猜你喜欢
      • 2021-08-17
      • 2019-06-04
      • 2021-03-08
      • 1970-01-01
      • 2019-01-03
      • 2019-07-16
      • 2018-06-05
      • 2020-10-20
      • 2018-01-20
      相关资源
      最近更新 更多