@robocop45
Only python

Почему в вебсокете пользователь является анонимом?

Всем привет, у меня почему-то именно на удаленном сервере(ubuntu 20) пользователь в self.scope, является анонимом. Сам я на винде

consumers.py
class CallConsumer(AsyncWebsocketConsumer):
    """
       WebSocket-потребитель для отправки уведомлений пользователям.
    """
    async def connect(self) -> None:
        """Устанавливает соединение и проверяет юзера на аутентификацию"""

        self.user = self.scope["user"]
        print(self.scope)
        self.group_name = 'notifications'
        await self.channel_layer.group_add(
            self.group_name,
            self.channel_name
        )
        await self.accept()
        print('connected ws')

    async def disconnect(self, close_code) -> None:
        """Отключает соединение"""

        await self.channel_layer.group_discard(
            self.group_name,
            self.channel_name)

    async def send_notification(self, event: dict) -> None:
        """ Отправляет уведомление конкретному пользователю"""
        print(self.scope['user'])
        if self.scope['user'].id == int(event['data'][
                                            'employee_number']):  # сравниваем id текущего пользователя со списком из контекста(send_simple_notification)
            await self.send(text_data=json.dumps(event['data'], ensure_ascii=False))


asgi.py
import os
from channels.auth import AuthMiddlewareStack
from channels.routing import ProtocolTypeRouter, URLRouter

from django.core.asgi import get_asgi_application
from apps.middleware import TokenAuthMiddleware
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "cpm.settings")

django_asgi_app = get_asgi_application()


from apps.call.urls import websocket_urlpatterns

application = ProtocolTypeRouter(
    {
        "http": django_asgi_app,
        "websocket": TokenAuthMiddleware(URLRouter(websocket_urlpatterns))

    }
)


TokenAuthMiddleware - это самописный класс, который берет jwt токен из query params и аунтифицирует пользователя

TokenAuthMiddleware


from urllib.parse import parse_qs
from channels.db import database_sync_to_async
import jwt

from django.contrib.auth import get_user_model
from django.contrib.auth.models import AnonymousUser
from django.utils.translation import gettext_lazy as _
from rest_framework.exceptions import AuthenticationFailed
from rest_framework_simplejwt.authentication import JWTTokenUserAuthentication
from rest_framework_simplejwt.exceptions import InvalidToken, TokenError
from rest_framework_simplejwt.tokens import UntypedToken

from cpm import settings

User = get_user_model()


class SimpleJWTAuthentication:
    """
    Simple JWT token based authentication.

    Clients should authenticate by passing the token in the Authorization header.
    For example:

        Authorization: Bearer <token>
    """

    def __init__(self):
        self.jwt_auth = JWTTokenUserAuthentication()

    def authenticate(self, token):
        user = self.get_user_from_token(token)

        if not user or not user.is_active:
            return AnonymousUser(), None

        return user

    def get_user_from_token(self, token):
        try:
            payload = jwt.decode(token, settings.SECRET_KEY, algorithms=[settings.SIMPLE_JWT['ALGORITHM']])
            user_id = payload['user_id']
            return User.objects.get(id=user_id)
        except jwt.ExpiredSignatureError:
            raise AuthenticationFailed(_("Token has expired."))
        except jwt.InvalidTokenError:
            raise AuthenticationFailed(_("Invalid token."))
        except User.DoesNotExist:
            return None


@database_sync_to_async
def get_user(scope):
    """
    Return the user model instance associated with the given scope.
    If no user is retrieved, return an instance of `AnonymousUser`.
    """
    # postpone model import to avoid ImproperlyConfigured error before Django
    # setup is complete.
    from django.contrib.auth.models import AnonymousUser

    if "token" not in scope:
        raise ValueError(
            "Cannot find token in scope. You should wrap your consumer in "
            "TokenAuthMiddleware."
        )
    token = scope["token"]
    user = None
    try:
        auth = SimpleJWTAuthentication()
        user = auth.authenticate(token)
    except AuthenticationFailed:
        pass
    return user or AnonymousUser()


class TokenAuthMiddleware:
    """
    Custom middleware that takes a token from the query string and authenticates via
    JWT tokens.
    """

    def __init__(self, app):
        # Store the ASGI application we were passed
        self.app = app

    async def __call__(self, scope, receive, send):
        token = parse_qs(scope["query_string"].decode("utf8"))["token"][0]

        try:
            # This will automatically validate the token and raise an error if token is invalid
            UntypedToken(token)
        except (InvalidToken, TokenError) as e:
            # Token is invalid
            print(e)
            return None
        else:
            decoded_data = jwt.decode(token, settings.SECRET_KEY, algorithms=["HS256"])
            print(decoded_data)
            scope["token"] = token
            scope["user"] = await get_user(scope)

        return await self.app(scope, receive, send)


urls
websocket_urlpatterns = [
path(r"ws/notifications/", CallConsumer.as_asgi()),
]

js код для открытия ws

const token = "токен";
const socket1 = new WebSocket(`wss://${window.location.host}/ws/notifications/?token=${token}`);
socket1.addEventListener('open', (event) => {
    console.log('WebSocket connection opened:', event);
    console.log('Открыто');
    // Теперь, когда соединение открыто, вы можете отправлять сообщения на сервер
    // Например, отправка сообщения для запроса уведомлений
    // Запускаем метод receive
    
});


// Обработка события получения сообщения от сервера
socket1.addEventListener('message', (event) => {
    console.log('Received message from server:', event.data);
    // Здесь вы можете обработать полученное сообщение
});

// Обработка события закрытия соединения
socket1.addEventListener('close', (event) => {
    console.log('WebSocket connection closed:', event);
});

// Обработка события ошибки
socket1.addEventListener('error', (event) => {
    console.error('WebSocket error:', event);
});

терминал:

(<django.contrib.auth.models.AnonymousUser object at 0x7fb2e0d93790>, None)


Я перезапускаю сервер, генерирую токен jwt, вставляю его в js код, но пользователь все равно аноним. На локалке такой проблемы нет, какие есть варианты решения?
  • Вопрос задан
  • 47 просмотров
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы