在使用令牌身份验证时,如何在django通道中的websocket连接中对用户进行身份验证
我在项目中使用前端框架()和RESTAPI。另外,对于JSON web令牌身份验证,我正在使用。成功登录后,将向用户提供令牌。此令牌被传递到每个请求中,以获取任何与API相关的内容 现在我想整合到我的项目中。因此,在成功登录之后,当客户端接收到令牌时,我想启动websocket连接。然后在服务器(消费者)上,我想检查请求的用户是否是匿名的。如果请求的用户是匿名的,我想关闭连接或接受它 这就是我到目前为止所做的: 客户端:在使用令牌身份验证时,如何在django通道中的websocket连接中对用户进行身份验证,django,rest,django-rest-framework,token,django-channels,Django,Rest,Django Rest Framework,Token,Django Channels,我在项目中使用前端框架()和RESTAPI。另外,对于JSON web令牌身份验证,我正在使用。成功登录后,将向用户提供令牌。此令牌被传递到每个请求中,以获取任何与API相关的内容 现在我想整合到我的项目中。因此,在成功登录之后,当客户端接收到令牌时,我想启动websocket连接。然后在服务器(消费者)上,我想检查请求的用户是否是匿名的。如果请求的用户是匿名的,我想关闭连接或接受它 这就是我到目前为止所做的: 客户端: const socket = new WebSocket("ws://"
const socket = new WebSocket("ws://" + "dev.site.com"+ "/chat/");
routing.py:
channel_routing = [
route("websocket.connect", ws_connect),
...
...
]
消费者:
def ws_connect(message):
# if the user is no anonymous
message.reply_channel.send({
"accept": True
})
# else
message.reply_channel.send({
"close": True
})
在中有一个来自http的decorator
@channel\u session\u user\u,它将提供一条消息。user
。但我使用的是令牌而不是会话。在使用令牌身份验证时,如何检查连接上的用户,以便接受或关闭连接。或者,如果有更好的方法,你能给我一个建议吗。谢谢。问题是浏览器不支持在websocket升级时传递jwt auth头,所以基本上就是这样。不久前我遇到了这个问题,并提出了通过查询参数传递令牌的解决方案-注意如果没有TLS,这是完全不安全的,因为您在URI中公开了身份验证。我再也无法获得确切的代码,但我的想法是:
from channels.generic.websockets import JsonWebsocketConsumer
from channels.handler import AsgiRequest
from rest_framework_jwt.serializers import VerifyJSONWebTokenSerializer
from jwt.exceptions import InvalidTokenError
from rest_framework.exceptions import ValidationError
class Consumer(JsonWebsocketConsumer):
def connect(self, message, **kwargs):
# construct a fake http-like request object from the message
message.content.setdefault('method', 'FAKE')
request = AsgiRequest(message)
# validate the token
try:
VerifyJSONWebTokenSerializer().validate(request.GET)
super().connect(message, **kwargs)
except (KeyError, InvalidTokenError, ValidationError,):
# token is either not available or invalid
# so we disconnect the user
message.reply_channel.send({'close': True})
将消费者注册到
channel_routing = [
...
route_class(Consumer, path=r'^my-ws-endpoint$'),
]
在浏览器端,您可以通过在websocket URI中将令牌作为查询参数传递来建立websocket连接:
let-token:string='my-token';//拿到代币
让wsHandler:$WebSocket=new$WebSocket('wss://example.com/my-ws-endpoint/?token=“+代币,…);
然后,您可以在类似于http中的@channel\u session\u user\u的decorator中提取auth check代码,只需修饰连接例程,或者在使用基于类的路由时将代码提取到mixin
我想重申,如果不使用加密,这种方法是完全不安全的,因此在生产中,URI应该从https/wss
开始
编辑:这是一个用于DRF令牌身份验证的方法,适用于基于函数和基于类的路由。它与我的方法几乎相同,构造一个请求对象并将其传递给身份验证器。@hoefling的答案是我的指南。我对认证用户的两件事感到困惑
这个代币怎么办
- 您可以将令牌作为查询字符串传递并获取该查询参数。了解有关如何获取查询参数的更多信息
- 或者,如果您已经在请求的授权头中传递了它,那么您可以从那里获得它,就像@hoefling对他的回答所做的那样。记住先假装那个请求李>
如何验证该令牌并获取用户
- 最后,
VerifyJSONWebTokenSerializer
类是验证令牌并获取该令牌的用户对象所需的全部。(谢谢@hoefling!)您可以阅读django rest framework jwt的实际代码
所以,我最终是这样做的:
def ws_connect(message):
message.content.setdefault('method', 'FAKE')
django_request = AsgiRequest(message)
token = django_request.GET['token'].split(' ')[1]
try:
data = {'token': token}
valid_data = VerifyJSONWebTokenSerializer().validate(data)
user = valid_data['user']
...
...
message.reply_channel.send({
"accept": True
})
except (KeyError, InvalidTokenError, ValidationError,):
...
...
message.reply_channel.send({
"text": "Authentication error",
"close": True
})
伟大的你的回答对我帮助很大!谢谢。很高兴我能帮忙!https/wss expose thr URI?@injaon您的身份验证令牌在未加密的情况下公开,例如在发生MITM攻击的情况下。