Channels: AuthMiddlewareStack does not work with AsyncHttpConsumers in Channels 3

Created on 30 Oct 2020  路  11Comments  路  Source: django/channels

Hello,

I upgrade Django channels to ver. 3.0.0 and discovered that few features stopped working for me.
This is happening in the manage.py runserver command.
Haven't tried in staging/production yet.

In Django channels ver. 2.4.0, I had the routing.py configuration file set up like this:

from django.urls import re_path

from channels.auth import AuthMiddlewareStack
from channels.routing import ProtocolTypeRouter, URLRouter
from channels.http import AsgiHandler

from apps.logs.ws import consumers as logs_consumers


application = ProtocolTypeRouter({
    "http": AuthMiddlewareStack(
        URLRouter([
            re_path(r"^admin/logs/live/$", logs_consumers.LogsSSEConsumer),
            re_path(r"", AsgiHandler)
        ])
    )
})

The LogsSSEConsumer consumer class is inheriting from AsyncHttpConsumer.

Everything was working on ver. 2.4 and I could access to self.scope["user"] in the consumers handle method.

Now upgrading to channels ver. 3 I updated asgi.py file like this:

import os

from django.urls import re_path
from django.core.asgi import get_asgi_application

from channels.routing import ProtocolTypeRouter, URLRouter
from channels.auth import AuthMiddlewareStack

from apps.logs.ws import consumers as logs_consumers


os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'config.settings')

application = ProtocolTypeRouter({
    "http": AuthMiddlewareStack(
        URLRouter([
            re_path(r"^admin/logs/live/$", logs_consumers.LogsSSEConsumer.as_asgi()),
            re_path(r"", get_asgi_application()),
        ])
    ),
})

Everything is broken now, a lot of 500 errors showing up in the browser and nothing is working.
In the terminal, there are no errors.

If I remove AuthMiddlewareStack wrapper, then everything starts working, except LogsSSEConsumer consumer, because i cannot access self.scope["user"] anymore.

If I remove self.scope["user"] lines from the consumers handler method, then everything is working again.

I don't know, am I setting up those routes wrongly or how can I set up now AsyncHttpConsumer consumers so I can get access to self.scope["user"].

Same question is, how can i setup AllowedHostsOriginValidator wrapper with AsyncHttpConsumer consumers?

OS: Docker - python:3.8.6-slim
Dependencies:
Django==3.1.2
channels==3.0.0
channels_redis==3.1.0
django-redis==4.12.1
redis==3.5.3
...

Most helpful comment

@gghildyal Super. Good to hear! Thanks for the confirmation.

3.0.1 will be as soon as I can get the moment.

All 11 comments

I am able to access self.scope["user"] with the following routing:

application = ProtocolTypeRouter(
    {
        "websocket": AuthMiddlewareStack(
            URLRouter(
                [
                    re_path(r"^mywebsocketurl/$", MyConsumer.as_asgi()),
                ]
            )
        ),
        "http": get_asgi_application(),
    }
)

Python 3.9.0

Dependencies:
Django==3.1.2
channels==3.0.0
channels-redis==3.2.0
aioredis==1.3.1
hiredis==1.1.0

Not installed:
django-redis==4.12.1
redis==3.5.3

Edited: works with Python 3.8.6 too.

I am able to access self.scope["user"] with the following routing:

application = ProtocolTypeRouter(
    {
        "websocket": AuthMiddlewareStack(
            URLRouter(
                [
                    re_path(r"^mywebsocketurl/$", MyConsumer.as_asgi()),
                ]
            )
        ),
        "http": get_asgi_application(),
    }
)

Python 3.9.0

Dependencies:
Django==3.1.2
channels==3.0.0
channels-redis==3.2.0
aioredis==1.3.1
hiredis==1.1.0

Not installed:
django-redis==4.12.1
redis==3.5.3

Edited: works with Python 3.8.6 too.

Hei @ipaleka,

I am using AsyncHttpConsumer consumer, which I understand has to be under "http" key in the ProtocolTypeRouter.

Tried to put my LogsSSEConsumer under the "websocket" key, but then that route is not found.

There's an issue with SessionMiddleware in #1551.

If I remove AuthMiddlewareStack wrapper, then everything starts working, except LogsSSEConsumer consumer, because i cannot access self.scope["user"] anymore.

This looks as if it's likely related. Let's work on a fix for that.
Thanks for the report.

Hi all. I've got #1553, which I'm hoping will resolve this. Can I ask if anyone can give that a run to confirm? Thanks.

Hei @carltongibson

I have tested the same code with the fix-session-middleware branch and everything is working for me, including WebSockets sessions.
Tested manually in the development environment with multiple tabs and users.

Hi @KStenK. Thank you for taking the time to test and confirm that!

I shall put together a point release... 馃憤

I am seeing this issue when using async Ariandne Graphql API. Things were working find with Channels 2.4.0 but after upgrading to 3.0, although the GraphQL interactive API works fine, apollo graphql-codegen fails to fetch the schema using the introspection query.

The error I get is

RuntimeError: Unexpected ASGI message 'http.response.start' sent, after response already completed.

Bypassing SessionMiddleware 'send' method makes everything work fine again. After debugging, it seems like the stack is handling a http.response.start followed by an http.response.body followed by another http.response.start (with a content-length one byte greater than the one advertised in the first http.response.start!). I am guessing because the response body is a bit bigger I see the failure only for introspection responses.

The application routing I am using is

graphql_app = get_protected_app(
    AuthMiddlewareStack(
        get_graphql_app(),
    ),
)


application = ProtocolTypeRouter(
    {
        'http': URLRouter(
            [
                path('graphql/', graphql_app),
                re_path(r'', get_asgi_application()),
            ],
        ),
    },
)

@KStenK I will test your branch as well to see if it fixes my issue as well.

@gghildyal You made the exact same comment here: https://github.com/django/channels/issues/1551#issuecomment-721443093. As I replied there:

@gghildyal is this with 3.0.0 or my branch in #1553? It might be worth a separate issue as it doesn't look necessarily like the same thing. It would be helpful if we could reduce it to a smaller example.

By smaller example I mean without get_protected_app and get_graphql_app which aren't part of Channels.

@carltongibson Oops sorry, and I thought I lost my comment from late last night!

This was with 3.0.0 and not your branch. Having tested my scenario with fix-session-middleware, things work fine! Thanks @carltongibson and apologies for the multiple comments.

@gghildyal Super. Good to hear! Thanks for the confirmation.

3.0.1 will be as soon as I can get the moment.

3.0.1 is available on PyPI now: https://pypi.org/project/channels/3.0.1/

Was this page helpful?
0 / 5 - 0 ratings

Related issues

ademidun picture ademidun  路  3Comments

nefegago picture nefegago  路  4Comments

shitone picture shitone  路  3Comments

fakabbir picture fakabbir  路  5Comments

Pazitos10 picture Pazitos10  路  5Comments