You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Django Channels中使用Knox令牌认证WebSocket连接?

在Django Channels中使用django-rest-knox进行WebSocket令牌认证

我明白你的困扰——Knox的令牌是加密存储的,没法直接用前端传的令牌字符串去数据库里查用户,必须借助Knox自身的验证机制来处理。下面我给你一步步拆解解决方案:

1. 编写自定义认证中间件

Channels的WebSocket连接是异步的,所以我们需要写一个异步的中间件,负责解析令牌、验证并把用户绑定到连接的scope中。

首先创建一个中间件文件(比如middleware.py),代码如下:

from channels.middleware import BaseMiddleware
from channels.db import database_sync_to_async
from urllib.parse import parse_qsl
from django.contrib.auth.models import AnonymousUser
from knox.models import AuthToken

# 异步函数:通过Knox令牌获取用户
@database_sync_to_async
def get_authenticated_user(token):
    try:
        # Knox令牌的前8位是存在数据库中的token_key,先通过它找到令牌对象
        token_obj = AuthToken.objects.get(token_key=token[:8])
        
        # 先检查令牌是否过期
        if token_obj.expired():
            return AnonymousUser()
        
        # 用Knox自带的token_compare方法验证完整令牌(因为数据库存的是哈希值,不能直接比对字符串)
        if token_obj.token_compare(token):
            return token_obj.user
        else:
            return AnonymousUser()
    except AuthToken.DoesNotExist:
        # 令牌不存在或无效
        return AnonymousUser()

# Channels认证中间件
class KnoxTokenAuthMiddleware(BaseMiddleware):
    async def __call__(self, scope, receive, send):
        # 从WebSocket连接的查询参数中提取令牌
        query_params = dict(parse_qsl(scope["query_string"].decode()))
        raw_token = query_params.get("token", "")
        
        # 验证令牌并获取用户
        scope["user"] = await get_authenticated_user(raw_token)
        
        # 继续处理连接
        return await super().__call__(scope, receive, send)

代码解释:

  • database_sync_to_async:把同步的数据库操作包装成异步,适配Channels的异步环境。
  • token[:8]:Knox生成的令牌前8位是唯一标识(存在数据库的token_key字段),后面的部分是哈希后的内容,所以先通过前8位找到对应的令牌对象。
  • token_compare():Knox提供的方法,会把前端传的原始令牌哈希后和数据库中存储的哈希值比对,确保令牌有效。
  • expired():检查令牌是否过期,避免使用已失效的令牌。

2. 配置Channels路由

在你的Channels路由文件(比如routing.py)中,用刚才写的中间件包裹WebSocket路由:

from channels.routing import ProtocolTypeRouter, URLRouter
from django.urls import path
from . import consumers
from .middleware import KnoxTokenAuthMiddleware

application = ProtocolTypeRouter({
    # WebSocket路由配置
    "websocket": KnoxTokenAuthMiddleware(
        URLRouter([
            path("ws/your-path/", consumers.YourConsumer.as_asgi()),
            # 其他WebSocket路由...
        ])
    ),
})

这样所有WebSocket连接都会先经过Knox令牌认证,认证通过后,你就可以在Consumer中通过self.scope["user"]获取当前用户了。

3. 前端传递令牌

前端在建立WebSocket连接时,需要把Knox令牌作为查询参数传递,比如:

// 假设你已经从后端拿到了Knox令牌,存在knoxToken变量中
const socket = new WebSocket(`ws://your-domain.com/ws/your-path/?token=${knoxToken}`);

注意事项

  • 安全问题:生产环境一定要用wss(WebSocket Secure)协议,避免令牌明文传输。
  • 令牌过期处理:如果令牌过期,中间件会返回AnonymousUser,你可以在Consumer中判断用户是否匿名,主动关闭连接或返回错误信息。
  • 令牌刷新:如果你的应用使用Knox的令牌刷新机制,前端需要在令牌过期前刷新,并重新建立WebSocket连接。

内容的提问来源于stack exchange,提问作者Brian Min

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.13 08:17:17