Django使用Header(子协议)传递JWT Token
默认情况下,服务端会开启一个WebSocket服务端,并一直处于监听状态。浏览器利用js脚本发起连接,并将内容通过WebSocket发送给服务端。只要发送的格式符合服务端的定义,理论上讲,服务端会无条件执行任何请求。这种情况下是很危险的。安全的做法是WebSocket请求也需要携带Token进行访问。
使用Header(子协议)传递JWT Token
携带token有很多方式,例如直接发到URL请求路径中。但是这样会涉及到数据泄露的情况。比较安全的方式是放在header头中或者使用子协议(protocols)传输Token。
环境:Django并且使用的websockets
首先重写WebsocketConsumer类的connect方法
class MyWebSocket(AsyncJsonWebsocketConsumer):
async def connect(self):
try:
import jwt
# 获取token
self.service_uid = self.scope["subprotocols"][0]
# 使用jwt解析token
decoded_result = jwt.decode(self.service_uid, settings.SECRET_KEY, algorithms=["HS256"])
if decoded_result:
self.user_id = decoded_result.get('user_id')
self.chat_group_name = "user_" + str(self.user_id)
# 收到连接时候处理,
await self.channel_layer.group_add(
self.chat_group_name,
self.channel_name
)
###
# 重点:这里需要将token传入,否则客户端收不到你发的消息
await self.accept(subprotocol=self.service_uid)
# 发送连接成功
await self.send_json({"message":"连接成功", "sender":"系统"})
except InvalidSignatureError as e:
print(e.__str__())
await self.disconnect(None)
async def disconnect(self, close_code):
# Leave room group
await self.channel_layer.group_discard(self.chat_group_name, self.channel_name)
try:
await self.close(close_code)
except Exception:
pass
前端部分可以这样写
function initWebSocket (e) {
const token = util.cookies.get('token')
if (token) {
const wsUri = util.wsBaseURL() + 'ws/'
this.socket = new WebSocket(wsUri, [token])// token在这里传输
this.socket.onerror = webSocketOnError
this.socket.onmessage = webSocketOnMessage
this.socket.onclose = closeWebsocket
}
}
最后查看效果,我们在请求头和响应头中看到了token