jazzband/django-rest-knox

How to check token user for channels middeware?

AlexCernik opened this issue · 1 comments

Hi, I am using channels with drf and like connect only users authenticated to websocket, how to possible?. This my middleware code and asgy.py. Thanks.

from django.contrib.auth.models import AnonymousUser
from channels.db import database_sync_to_async
from channels.middleware import BaseMiddleware

@database_sync_to_async
def get_user(token_key):
    # check
    pass

class TokenAuthMiddleware(BaseMiddleware):
    def __init__(self, inner):
        super().__init__(inner)

    async def __call__(self, scope, receive, send):

        try:
            token_key = dict(scope['headers'])[b'sec-websocket-protocol'].decode('utf-8')
            print(token_key)
        except ValueError:
            token_key = None
        scope['user'] = AnonymousUser() if token_key is None else await get_user(token_key)
        return await super().__call__(scope, receive, send)
application = ProtocolTypeRouter({
    'http': django_asgi_app,
    'websocket': TokenAuthMiddleware(URLRouter(ws_urlspatterns))
})

I don't know how to speak much English, I speak Spanish, sorry.

This is how I've implemented custom token authentication middleware

from django.utils.translation import gettext_lazy as _
from channels.auth import AuthMiddlewareStack
from rest_framework.authtoken.models import Token
from django.contrib.auth.models import AnonymousUser
from knox.auth import TokenAuthentication
from asgiref.sync import sync_to_async


class TokenAuthMiddleware:
    def __init__(self, inner):
        self.inner = inner

    async def __call__(self, scope, receive, send):
        headers = dict(scope['headers'])

        if b'cookie' in headers:
            cookie_header = str(headers[b'cookie'])
            if "X-Authorization=" in cookie_header:
                for slice in cookie_header.split(";"):
                    if " X-Authorization=" in slice:
                        token = slice.replace(" X-Authorization=", "").replace("'","")
                        token = token.encode()
                        try:
                            auth = TokenAuthentication()
                            token_obj = await sync_to_async(auth.authenticate_credentials)(token)
                            scope['user'] = token_obj[0]

                        except Exception as error:
                            print("Failed to get authenticate user: ", error)
                            scope['user'] = AnonymousUser()
                 
        return await self.inner(scope, receive, send)

TokenAuthMiddlewareStack = lambda inner: TokenAuthMiddleware(AuthMiddlewareStack(inner))

in the frontend just make sure to add the token as a cookie:

document.cookie = 'X-Authorization=' + token + '; path=/';