django / channels

Developer-friendly asynchrony for Django
https://channels.readthedocs.io
BSD 3-Clause "New" or "Revised" License
6.11k stars 800 forks source link

Using django channels causing login and session getting corrupted. #236

Closed ahumblenerd closed 8 years ago

ahumblenerd commented 8 years ago

[2016/07/07 15:58:21] HTTP GET /accounts/login/ 200 [0.06, 127.0.0.1:60921]

Url patterns urlpatterns = [

url(r'^admin/', admin.site.urls),
url(r'^new/$', views.new_room, name='new_room'),
url(r'^accounts/profile/$',  views.testView, name='testView'),
url(r'^accounts/', include('allauth.urls')),
url(r'^(?P<label>[\w-]{,50})/$', views.chat_room, name='chat_room'),

]

routing.py

channel_routing = {

'http.request': StaticFilesConsumer(),
'websocket.connect': consumers.ws_connect,
'websocket.receive': consumers.ws_receive,
'websocket.disconnect': consumers.ws_disconnect,

}

andrewgodwin commented 8 years ago

Can you please provide more information? In particular:

Please reopen when you have these - thanks!

ahumblenerd commented 8 years ago
System check identified no issues (0 silenced).
July 07, 2016 - 19:48:49
Django version 1.9.3, using settings 'chat.settings'
Starting Channels development server at http://127.0.0.1:8000/
Channel layer default (asgi_redis.RedisChannelLayer)
Quit the server with CONTROL-C.
Session data corrupted
2016-07-07 19:48:52,075 - WARNING - base - Session data corrupted
[2016/07/07 19:48:52] HTTP GET /admin/chat/room/ 302 [0.05, 127.0.0.1:64972]
Session data corrupted
2016-07-07 19:48:52,123 - WARNING - base - Session data corrupted
[2016/07/07 19:48:52] HTTP GET /admin/login/ 200 [0.07, 127.0.0.1:64972]
Session data corrupted
2016-07-07 19:48:53,339 - WARNING - base - Session data corrupted
[2016/07/07 19:48:53] HTTP GET /admin/login/ 200 [0.05, 127.0.0.1:64972]
[2016/07/07 19:48:53] HTTP GET /static/admin/css/base.css 304 [0.02, 127.0.0.1:64972]
[2016/07/07 19:48:53] HTTP GET /static/admin/css/login.css 200 [0.04, 127.0.0.1:64998]
[2016/07/07 19:48:53] HTTP GET /static/admin/css/fonts.css 304 [0.06, 127.0.0.1:64998]
[2016/07/07 19:48:53] HTTP GET /static/admin/fonts/Roboto-Regular-webfont.woff 304 [0.03, 127.0.0.1:64972]
[2016/07/07 19:48:54] HTTP GET /static/admin/fonts/Roboto-Light-webfont.woff 304 [0.04, 127.0.0.1:64998]
Session data corrupted
2016-07-07 19:49:15,575 - WARNING - base - Session data corrupted
[2016/07/07 19:49:15] HTTP POST /admin/login/ 302 [0.07, 127.0.0.1:64998]
[2016/07/07 19:49:15] HTTP GET /admin/chat/room/ 302 [0.05, 127.0.0.1:64998]
[2016/07/07 19:49:15] HTTP GET /admin/login/ 200 [0.05, 127.0.0.1:64998]
[2016/07/07 19:49:23] HTTP POST /admin/login/ 302 [0.05, 127.0.0.1:64998]
[2016/07/07 19:49:23] HTTP GET /admin/chat/room/ 302 [0.05, 127.0.0.1:64998]
[2016/07/07 19:49:23] HTTP GET /admin/login/ 200 [0.05, 127.0.0.1:64998]
[2016/07/07 19:49:53] HTTP GET /admin/login/ 200 [0.04, 127.0.0.1:64998]
[2016/07/07 19:49:54] HTTP GET /static/admin/css/base.css 304 [0.03, 127.0.0.1:64998]
[2016/07/07 19:49:54] HTTP GET /static/admin/css/login.css 304 [0.03, 127.0.0.1:64972]
[2016/07/07 19:49:54] HTTP GET /static/admin/css/fonts.css 304 [0.04, 127.0.0.1:64972]
[2016/07/07 19:49:54] HTTP GET /static/admin/fonts/Roboto-Regular-webfont.woff 304 [0.03, 127.0.0.1:64998]
[2016/07/07 19:49:54] HTTP GET /static/admin/fonts/Roboto-Light-webfont.woff 304 [0.04, 127.0.0.1:64972]
[2016/07/07 19:49:57] HTTP POST /admin/login/ 200 [0.08, 127.0.0.1:64972]
[2016/07/07 19:49:57] HTTP GET /static/admin/fonts/Roboto-Bold-webfont.woff 304 [0.03, 127.0.0.1:64972]
[2016/07/07 19:50:02] HTTP POST /admin/login/ 302 [0.06, 127.0.0.1:64972]
[2016/07/07 19:50:02] HTTP GET /admin/chat/room/ 302 [0.05, 127.0.0.1:64972]
[2016/07/07 19:50:02] HTTP GET /admin/login/ 200 [0.05, 127.0.0.1:64972]

Requirements File

asgi-redis==0.8.3 asgiref==0.9 autobahn==0.12.1 channels==0.9.3 daphne==0.9.1 defusedxml==0.4.1 dj-database-url==0.4.0 Django==1.9.3 django-allauth==0.25.2 haikunator==1.0.1 msgpack-python==0.4.7 oauthlib==1.1.2 psycopg2==2.6.1 python-openid==2.2.5 python3-openid==3.0.10 redis==2.10.5 requests==2.10.0 requests-oauthlib==0.6.1 six==1.10.0 Twisted==15.5.0 txaio==2.2.1 zope.interface==4.1.3

@login_required
def chat_room(request, label):
    """
    Room view - show the room, with latest messages.

    The template for this view has the WebSocket business to send and stream
    messages, so see the template for where the magic happens.
    """
    # If the room with the given label doesn't exist, automatically create it
    # upon first visit (a la etherpad).
    print(request.user)
    print(label)
    print("chat room loaded")
    room, created = Room.objects.get_or_create(label=label)
    try:
        project = Project.objects.get(room=room)
    except:

        return HttpResponseRedirect('/new/')
    # We want to show the last 50 messages, ordered most-recent-last
    messages = reversed(room.messages.order_by('-timestamp')[:50])

    if True :

        return render(request, "chat/room.html", {
            'room': room,
            'messages': messages,
        })
    else:

        return HttpResponseRedirect('/accounts/login/')

I have created a model called project. And when a project is created a room is allocated for the team. Now I am checking before presenting the view after checking whether he has the permissions to view them. But when I do that the moment I add a @login_required decorater it starts showing this issue. Also the admin panel keeps redirecting to the same login page.

The error starts showing up if i navigate from one view to another and then come back. When I do that the session gets corrupted

andrewgodwin commented 8 years ago

Firstly, you're very far behind on your versions of channels, daphne, etc - upgrade them all (channels is up to 0.16 now), and see if that helps.

ahumblenerd commented 8 years ago
Starting Channels development server at http://127.0.0.1:8000/
Channel layer default (asgi_redis.RedisChannelLayer)
Quit the server with CONTROL-C.
2016-07-08 03:11:16,266 - INFO - worker - Listening on channels http.request, websocket.connect, websocket.disconnect, websocket.receive
2016-07-08 03:11:16,267 - INFO - worker - Listening on channels http.request, websocket.connect, websocket.disconnect, websocket.receive
2016-07-08 03:11:16,269 - INFO - worker - Listening on channels http.request, websocket.connect, websocket.disconnect, websocket.receive
2016-07-08 03:11:16,270 - INFO - worker - Listening on channels http.request, websocket.connect, websocket.disconnect, websocket.receive
Session data corrupted
[2016/07/08 03:11:31] HTTP GET /accounts/login/ 200 [0.54, 127.0.0.1:49306]
Unhandled Error
Traceback (most recent call last):
  File "/Users/Jarvis/Desktop/test/channels-example/env/lib/python3.4/site-packages/channels/management/commands/runserver.py", line 82, in inner_run
    http_timeout=60,  # Shorter timeout than normal as it's dev
  File "/Users/Jarvis/Desktop/test/channels-example/env/lib/python3.4/site-packages/daphne/server.py", line 55, in run
    reactor.run(installSignalHandlers=self.signal_handlers)
  File "/Users/Jarvis/Desktop/test/channels-example/env/lib/python3.4/site-packages/twisted/internet/base.py", line 1194, in run
    self.mainLoop()
  File "/Users/Jarvis/Desktop/test/channels-example/env/lib/python3.4/site-packages/twisted/internet/base.py", line 1203, in mainLoop
    self.runUntilCurrent()
--- <exception caught here> ---
  File "/Users/Jarvis/Desktop/test/channels-example/env/lib/python3.4/site-packages/twisted/internet/base.py", line 825, in runUntilCurrent
    call.func(*call.args, **call.kw)
  File "/Users/Jarvis/Desktop/test/channels-example/env/lib/python3.4/site-packages/daphne/server.py", line 75, in backend_reader
    self.factory.dispatch_reply(channel, message)
  File "/Users/Jarvis/Desktop/test/channels-example/env/lib/python3.4/site-packages/daphne/http_protocol.py", line 299, in dispatch_reply
    self.reply_protocols[channel].serverResponse(message)
  File "/Users/Jarvis/Desktop/test/channels-example/env/lib/python3.4/site-packages/daphne/http_protocol.py", line 206, in serverResponse
    raise ValueError("Got multiple Response messages for %s!" % self.reply_channel)
builtins.ValueError: Got multiple Response messages for http.response!!

asgi-redis==0.8.3 asgiref==0.13.3 autobahn==0.14.1 channels==0.16.0 daphne==0.14.2 defusedxml==0.4.1 dj-database-url==0.4.0 Django==1.9.7 django-allauth==0.25.2 haikunator==1.0.1 msgpack-python==0.4.7 oauthlib==1.1.2 psycopg2==2.6.1 python-openid==2.2.5 python3-openid==3.0.10 redis==2.10.5 requests==2.10.0 requests-oauthlib==0.6.1 six==1.10.0 Twisted==16.2.0 txaio==2.5.1 zope.interface==4.2.0 (env) Jarvis:channels-example Jarvis$ pip freeze asgi-redis==0.8.3 asgiref==0.13.3 autobahn==0.14.1 channels==0.16.0 daphne==0.14.2 defusedxml==0.4.1 dj-database-url==0.4.0 Django==1.9.7 django-allauth==0.25.2 haikunator==1.0.1 msgpack-python==0.4.7 oauthlib==1.1.2 psycopg2==2.6.1 python-openid==2.2.5 python3-openid==3.0.10 redis==2.10.5 requests==2.10.0 requests-oauthlib==0.6.1 six==1.10.0 Twisted==16.2.0 txaio==2.5.1 zope.interface==4.2.0

andrewgodwin commented 8 years ago

Your asgi_redis is still out of date, and the "multiple HTTP responses" points to an issue with the asgi layer - get that updated as well

ahumblenerd commented 8 years ago

2016-07-08 05:08:24,220 - INFO - worker - Listening on channels http.request, websocket.connect, websocket.disconnect, websocket.receive 2016-07-08 05:08:24,221 - INFO - worker - Listening on channels http.request, websocket.connect, websocket.disconnect, websocket.receive 2016-07-08 05:08:24,223 - INFO - worker - Listening on channels http.request, websocket.connect, websocket.disconnect, websocket.receive 2016-07-08 05:08:24,225 - INFO - worker - Listening on channels http.request, websocket.connect, websocket.disconnect, websocket.receive [2016/07/08 05:08:25] WebSocket CONNECT /chat/dark-shape-6473/ [127.0.0.1:53479] chat connect room=dark-shape-6473 client=127.0.0.1:53479 Session data corrupted AnonymousUser dark-shape-6473 chat room loaded [2016/07/08 05:08:29] HTTP GET /dark-shape-6473/ 200 [0.04, 127.0.0.1:53517] [2016/07/08 05:08:29] HTTP GET /static/chat.js 304 [0.02, 127.0.0.1:53522] [2016/07/08 05:08:29] HTTP GET /static/chat.css 304 [0.01, 127.0.0.1:53519] [2016/07/08 05:08:29] HTTP GET /static/normalize.css 304 [0.04, 127.0.0.1:53517] [2016/07/08 05:08:29] HTTP GET /static/reconnecting-websocket.min.js 304 [0.02, 127.0.0.1:53521] [2016/07/08 05:08:29] HTTP GET /static/skeleton.css 304 [0.05, 127.0.0.1:53518] [2016/07/08 05:08:29] HTTP GET /static/jquery-1.12.1.min.js 304 [0.03, 127.0.0.1:53520] [2016/07/08 05:08:29] WebSocket CONNECT /chat/dark-shape-6473/ [127.0.0.1:53538] chat connect room=dark-shape-6473 client=127.0.0.1:53538

asgi-redis==0.13.1 asgiref==0.13.3 autobahn==0.14.1 channels==0.16.0 daphne==0.14.2 dj-database-url==0.4.1 Django==1.9.7 django-allauth==0.25.2 haikunator==2.0.0 msgpack-python==0.4.7 oauthlib==1.1.2 psycopg2==2.6.2 python-openid==2.2.5 redis==2.10.5 requests==2.10.0 requests-oauthlib==0.6.1 six==1.10.0 Twisted==16.3.0 txaio==2.5.1 zope.interface==4.2.0

I have posted the code here. I am working with a channels example show at Heroku post

https://github.com/ahumblenerd/channels-example

andrewgodwin commented 8 years ago

OK, that got rid of all but the corrupted session error. I can't see any special session settings in your code, so it's not that.

Do you know if "session data corrupted" comes from the WebSocket connect or the HTTP GET view? That would help narrow down what's emitting it.

ahumblenerd commented 8 years ago

I just went back twisted version twisted version 16.2.0. I am able to send messages and receive messages now. I will keep on testing to see if this error crops up again and report them.

andrewgodwin commented 8 years ago

Oh, this is the twisted 16.2 issue? We're tracking that over in andrewgodwin/daphne#31 - the newest Daphne release (released after I told you to upgrade earlier) forces 16.2 or below to fix it!

ahumblenerd commented 8 years ago

@andrewgodwin I was using twisted 16.3 . Now I went back to twister 16.2and the issue is solved now. The session issue was caused by the old asgi like you said. Twisted 16.3broke the receive function. Its working as expected now

andrewgodwin commented 8 years ago

What do you mean by haywire? The above log looks normal to me - it's particularly verbose as you have passed -v 2 to the server or something, but none of the lines look bad.

ahumblenerd commented 8 years ago

@andrewgodwin All that was created when I went to a single url. I clicked on /new/ and at that very instant it starts giving a 200 and 302 multiple times.

andrewgodwin commented 8 years ago

The log shows the Heroku router showing you sent 4 GET requests to /new/, plus then six requests for static files that are presumably on that page - nothing seemingly out of the ordinary.

ahumblenerd commented 8 years ago

In the inspector it shows - Sorry too many redirects. I cannot understand what is causing multiple execution of the url

andrewgodwin commented 8 years ago

I'm afraid I can't help unless you can nail it down to something with Channels - some way to reproduce it locally on my machine. There are so many different things in a web stack or misconfigurations of Django that can lead to infinite redirect loops.

ahumblenerd commented 8 years ago

I will look into it and get back to you. Thanks for the help :)

anton-white commented 8 years ago

maybe it would help: I've just faced an issue with ERR_TOO_MANY_REDIRECTS on the staging server over HTTPS. Locally it worked just fine (plain HTTP). The reason was in SECURE_SSL_REDIRECT which I had TRUE on staging machine. I also have NGINX configured to redirect all requests from 80 port to 443. Dunno if NGINX' redirect was also involved in, but setting SECURE_SSL_REDIRECT to FALSE solved the problem.

andrewgodwin commented 8 years ago

That redirect problem is because you didn't have Nginx set to send X-Forwarded-Protocol to Django, so it didn't know that the connection was in fact SSL. We're getting native TLS support for Daphne soon that will make it easier to not screw this up.

anton-white commented 8 years ago

Very nice! Thanks a lot!

anton-white commented 8 years ago

Well, I began to have django-rest-swagger failing. With Gunicorn and SECURE_SSL_REDIRECT and X-Forwarded-Proto it worked. After switching to Daphne, swagger started to generate its base url with wrong scheme, i.e. http instead of https.

So, I tried some different cases:

Swagger generates its url like this: image

and seems like request.is_secure() returns False

anton-white commented 8 years ago

Made an API endpoint to check on staging server. This is what it says in both cases: with X-Forwarded-Proto and without it in Nginx config. image

SECURE_SSL_REDIRECT is False

andrewgodwin commented 8 years ago

Have you:

anton-white commented 8 years ago

@andrewgodwin Thanks a lot for your quick response as you always do! Yes, setting SECURE_PROXY_SSL_HEADER fixed the issue.

Just curious why there was no need in setting up SECURE_PROXY_SSL_HEADER when running under Gunicorn?

BTW:

Am I missing something obvious again with message['headers']?

andrewgodwin commented 8 years ago

I suspect gunicorn also has logic that parses that header and sets it using WSGI's url_scheme environment variable - I'll bring the same into Daphne at some point with a similar configurable header name, so you get to choose either that or native TLS termination so we can tell Django directly that it's secure.

As for headers not appearing in the consumers, it's only supplied on http.request and websocket.connect messages, so I'm guessing you were looking at websocket.receive?

anton-white commented 8 years ago

Exactly, I was looking at websocket.receive Now everything is much clearer. Thank you Andrew!

kodeshpa commented 7 years ago

@andrewgodwin @anton-white I am having exactly same issue, everything works well with gunicorn but moment i switch my sessions are corrupted. Any guidance is much appreciated.

My requirements

amqp==2.1.4
appdirs==1.4.3
asgi-rabbitmq==0.4.1
asgi-redis==1.3.0
asgiref==1.1.1
attrs==16.3.0
autobahn==0.18.2
Automat==0.5.0
billiard==3.5.0.2
boto==2.45.0
boto3==1.4.3
botocore==1.4.93
celery==4.0.2
channels==1.1.3
constantly==15.1.0
daphne==1.2.0
dj-database-url==0.4.2
Django==1.10.5
django-appconf==1.0.2
django-compat==1.0.14
django-compressor==2.1
django-cors-headers==2.0.0
django-debug-toolbar==1.6
django-extensions==1.7.5
django-filter==1.0.1
django-hijack==2.1.2
django-js-reverse==0.7.3
django-organizations==0.8.2
django-registration==2.2
django-rest-auth==0.9.0
django-storages==1.5.2
django-timezone-field==1.2
djangorestframework==3.5.3
djangorestframework-jwt==1.9.0
docutils==0.13.1
drf-dynamic-fields==0.1.1
drf-extensions==0.3.1
futures==3.1.1
gunicorn==19.6.0
incremental==16.10.1
jmespath==0.9.2
kombu==4.0.2
msgpack-python==0.4.8
packaging==16.8
pika==0.10.0
plivo==0.11.3
psycopg2==2.7.1
PyJWT==1.5.0
pyparsing==2.2.0
python-dateutil==2.6.0
pytz==2016.10
rcssmin==1.0.6
redis==2.10.5
requests==2.13.0
rjsmin==1.0.12
s3transfer==0.1.10
six==1.10.0
sqlparse==0.2.3
Twisted==17.1.0
txaio==2.7.0
ujson==1.35
vine==1.1.3
zope.interface==4.3.3

Setting

SECURE_PROXY_SSL_HEADER = ('x-forwarded-proto', 'https')
SECURE_SSL_REDIRECT = True
SESSION_COOKIE_SECURE = True
CSRF_COOKIE_SECURE = True

Nginx config

    location / {
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
            proxy_set_header Host $http_host;
            proxy_redirect off;
            proxy_next_upstream error;

            if ($http_x_forwarded_proto != "https") {
                rewrite ^(.*)$ https://$server_name$1 permanent;
         }
        proxy_pass http://wsserver;
            add_header Strict-Transport-Security "max-age=31536000; includeSubDomains;";  
    }
andrewgodwin commented 7 years ago

@kodeshpa Can you specify what you mean by "sessions getting corrupted"?

kodeshpa commented 7 years ago

Standard Django /login/ sessions. Sometimes it works but redirection post login is not working.

local/lib/python2.7/site-packages/django/contrib/sessions/backends/base.py lineno=117 funcname=decode Session data corrupted

andrewgodwin commented 7 years ago

Can I get a full stack trace of that error? We need to know if it is in Channels sessions or Django sessions.

kodeshpa commented 7 years ago

i ran pip install -U channels, only difference i see is Django channels are now it's working. (But everything is getting redirected to 301, It's on EC2 machine)

amqp==2.1.4 appdirs==1.4.3 asgi-rabbitmq==0.4.1 asgi-redis==1.3.0 asgiref==1.1.1 attrs==16.3.0 autobahn==0.18.2 Automat==0.5.0 billiard==3.5.0.2 boto==2.45.0 boto3==1.4.3 botocore==1.4.93 celery==4.0.2 channels==1.1.3 constantly==15.1.0 daphne==1.2.0 dj-database-url==0.4.2 Django==1.11 django-appconf==1.0.2 django-compat==1.0.14 django-compressor==2.1 django-cors-headers==2.0.0 django-debug-toolbar==1.6 django-extensions==1.7.5 django-filter==1.0.1 django-hijack==2.1.2 django-js-reverse==0.7.3 django-organizations==0.8.2 django-registration==2.2 django-rest-auth==0.9.0 django-storages==1.5.2 django-timezone-field==1.2 djangorestframework==3.5.3 djangorestframework-jwt==1.9.0 docutils==0.13.1 drf-dynamic-fields==0.1.1 drf-extensions==0.3.1 futures==3.1.1 gunicorn==19.6.0 incremental==16.10.1 jmespath==0.9.2 kombu==4.0.2 msgpack-python==0.4.8 packaging==16.8 pika==0.10.0 plivo==0.11.3 psycopg2==2.7.1 PyJWT==1.5.0 pyparsing==2.2.0 python-dateutil==2.6.0 pytz==2017.2 rcssmin==1.0.6 redis==2.10.5 requests==2.13.0 rjsmin==1.0.12 s3transfer==0.1.10 six==1.10.0 sqlparse==0.2.3 Twisted==17.1.0 txaio==2.7.0 ujson==1.35 vine==1.1.3 zope.interface==4.3.3