Django DRF websocket 通道 2 并使用来自 Simple JWT 的令牌进行授权
Posted
技术标签:
【中文标题】Django DRF websocket 通道 2 并使用来自 Simple JWT 的令牌进行授权【英文标题】:Django DRF websocket channels 2 and authorize with token from 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")
感谢回复
【问题讨论】:
【参考方案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
【讨论】:
以上是关于Django DRF websocket 通道 2 并使用来自 Simple JWT 的令牌进行授权的主要内容,如果未能解决你的问题,请参考以下文章
Ubuntu + Django(DRF) + channels(websocket)+NGINX + uwsgi 环境部署
Django rest 框架,Django 通道,Ionic2 - websocket 握手错误
如何通过 Django 通道 WebSocket 传递请求并调用 Django 视图
如何使用 Django 通道为 Django Rest Api 打开 Websocket?