Почему мое WebSocket-соединение отклоняется с сообщением «Unauthenticated user» в Django Channels даже при наличии действительного JWT-токена?

Я работаю над приложением для чата в реальном времени, используя Django Channels и WebSockets. Я реализовал пользовательскую систему аутентификации пользователей с помощью JWT-токенов и подключил аутентификацию на основе токенов к WebSocket-соединению с помощью промежуточного ПО Django Channels. Однако мое WebSocket-соединение постоянно отклоняется с сообщением: "Unauthenticated user attempted to connect.", несмотря на отправку действительного JWT-токена в заголовке Authorization.

Вот соответствующий код и настройки для моего проекта:

Настройка проекта:

  • Django Версия: 4.1.4
  • Django Channels Version: 4.0.0
  • ASGI Server: Daphne
  • Пользовательская модель: BasicUserProfile (которая хранит токен JWT в поле auth_token)

Код:

1. CustomAuthMiddleware - Middleware для аутентификации JWT:

import jwt
from datetime import datetime
from channels.middleware.base import BaseMiddleware
from authentication.models import BasicUserProfile
from django.contrib.auth.models import AnonymousUser
from django.conf import settings
from channels.db import database_sync_to_async

class CustomAuthMiddleware(BaseMiddleware):
    async def populate_scope(self, scope):
        user = scope.get('user', None)

        if user is None:
            token = self.get_token_from_headers(scope)
            if token:
                user = await self.get_user_by_token(token)
            else:
                user = AnonymousUser()

        scope['user'] = user

    def get_token_from_headers(self, scope):
        headers = dict(scope.get('headers', []))
        token = headers.get(b'authorization', None)
        if token:
            token_str = token.decode()
            if token_str.startswith("Bearer "):
                return token_str[len("Bearer "):]
        return None

    @database_sync_to_async
    def get_user_by_token(self, token):
        try:
            decoded_token = jwt.decode(token, settings.SECRET_KEY, algorithms=["HS256"])
            if decoded_token.get('exp') and decoded_token['exp'] < datetime.utcnow().timestamp():
                return AnonymousUser()

            user_profile = BasicUserProfile.objects.get(auth_token=token)
            return user_profile.user
        except (jwt.ExpiredSignatureError, jwt.DecodeError, BasicUserProfile.DoesNotExist):
            return AnonymousUser()

2. ChatConsumer - WebSocket Consumer:


Проблема:

Несмотря на реализацию аутентификации на основе JWT через промежуточное ПО, соединение WebSocket всегда отклоняется с сообщением:
"Unauthenticated user attempted to connect.".

Я отправляю JWT-токен как Bearer-токен в Authorization заголовке WebSocket-запроса, но соединение не проходит успешную аутентификацию.


Что я пробовал:

  1. Убедитесь, что токен правильно передается в заголовке.
  2. Проверили, что CustomAuthMiddleware правильно декодирует JWT и получает пользователя.
  3. Убедились, что JWT корректно работает для API-запросов (вне WebSocket).
  4. Отладили промежуточное ПО, чтобы убедиться, что токен принимается и декодируется.

Ожидаемое поведение:

Соединение WebSocket должно правильно аутентифицировать пользователя с помощью токена JWT и позволить ему подключиться и общаться с другими пользователями в режиме реального времени.


Вопрос:

Что может заставить WebSocket отклонить соединение с сообщением "Unauthenticated user attempted to connect.", несмотря на то, что в заголовке отправлен действительный JWT-токен? Есть ли проблема в том, как я обрабатываю аутентификацию токена для WebSockets в Django Channels, или есть что-то еще, что я могу упустить?

Вернуться на верх