Search code examples
pythondjangowebsocketdjango-channels

Django Channels consumers.py scope['user'] returns anonymousUser


I'm trying to create one to one chat but when I'm trying to get

self.scope['user']

it returns AnonymousUser

consumers.py

class ChatConsumer(SyncConsumer):

def websocket_connect(self,event):
    #error
    me = self.scope['user']
    other_username = self.scope['url_route']['kwargs']['username']
    other_user = User.objects.get(username=other_username)
    self.thread_obj = Thread.objects.get_or_create_personal_thread(me,other_user)
    self.room_name = f'{self.thread_obj.id}_service'

    print(f"{self.channel_name} connected")
    async_to_sync(self.channel_layer.group_add)(self.room_name,self.channel_name)
    self.send({
        'type':'websocket.accept'
    })
    

def websocket_receive(self,event):
    print(f"{self.channel_name} message received {event['text']}")
    msg = json.dumps({
        'text':event.get('text'),
        'username':self.scope['user'].username
    })
    async_to_sync(self.channel_layer.group_send)(
        self.room_name,
        {
            'type':'websocket.message',
            'text':msg
        }
    )

def websocket_message(self,event):
    print(f"{self.channel_name} message sent {event['text']}")
    self.send({
        'type':'websocket.send',
        'text':event.get('text')
    })

def websocket_disconnect(self,event):
    print(f"{self.channel_name} disconnected")
    async_to_sync(self.channel_layer.group_discard)(self.room_name,self.channel_name)
    print(event)

routing.py

from channels.routing import ProtocolTypeRouter,URLRouter
from django.urls import path
from .consumers import ChatConsumer,EchoConsumer
from channels.auth import AuthMiddlewareStack
import os
from django.core.asgi import get_asgi_application

os.environ.setdefault("DJANGO_SETTINGS_MODULE", "mysite.settings")
application = ProtocolTypeRouter({
    "http": get_asgi_application(),
    'websocket': AuthMiddlewareStack(
        URLRouter([
            path('ws/chat/',EchoConsumer()),
            path('ws/chat/<str:username>/',ChatConsumer()),
        ])
    )
})

I think the problem is here in auth.py:

@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 "session" not in scope:
        raise ValueError(
            "Cannot find session in scope. You should wrap your consumer in "
            "SessionMiddleware."
        )
    session = scope["session"]
    user = None
    try:
        
        user_id = _get_user_session_key(session)
        backend_path = session[BACKEND_SESSION_KEY]
    except KeyError:
        pass
    else:
        if backend_path in settings.AUTHENTICATION_BACKENDS:
            backend = load_backend(backend_path)
            user = backend.get_user(user_id)
            
            # Verify the session
            if hasattr(user, "get_session_auth_hash"):
                session_hash = session.get(HASH_SESSION_KEY)
                session_hash_verified = session_hash and constant_time_compare(
                    session_hash, user.get_session_auth_hash()
                )
                if not session_hash_verified:
                    session.flush()
                    user = None
    return user or AnonymousUser()

because codes under else not running


Solution

  • I've made some changes to the code that I took from the documentation and the result is like this

    class ChatConsumer(AsyncWebsocketConsumer):
    async def connect(self):
        me = self.scope['user']
        other_username = self.scope['url_route']['kwargs']['username']
        other_user =await sync_to_async(User.objects.get)(username=other_username)
        thread_obj =await sync_to_async(Thread.objects.get_or_create_personal_thread)(me,other_user)
        self.room_name = f'{thread_obj.id}_service'
        self.room_group_name = self.room_name
        await self.channel_layer.group_add(
            self.room_group_name,
            self.channel_name
        )
        await self.accept()
        
    async def disconnect(self, close_code):
        await self.channel_layer.group_discard(
            self.room_group_name,
            self.channel_name
        )
    
    async def receive(self, text_data):
        
        text_data_json = json.loads(text_data)
        message = text_data_json['message']
        await self.channel_layer.group_send(
            self.room_group_name,
            {
                'type': 'chat_message',
                'message': message
            }
        )
    
    async def chat_message(self, event):
        message = event['message']
        await self.send(text_data=json.dumps({
            'message': message
        }))