4

Once a message is sent through a Socket.IO connection from client (JS) to server (django/python) using django-socketio, is it possible to figure out which user was authenticated when the page was rendered?

In this case the view is being served up by django and it requires authentication -- normally on the server I would be able to do user = request.user, but in the events.py file the request.user just returns an AnonymousUser object. This makes sense because the websocket server is an entirely separate process than the django web server, and thus the user has not authenticated on that socket connection.

I'm thinking I'll have to come up with some clever code to embed the user ID into the message that is being sent to the server, and in that case I would need to add some handshaking to ensure that the end user cannot spoof it.

Has anyone come up with a clever solution to this problem?

skandocious
  • 814
  • 9
  • 21
  • While I don't have any code for you to reuse, this seems to be a known limitation of socket.io - http://stackoverflow.com/questions/4311180/how-to-send-cookies-when-connecting-to-socket-io-via-websockets – Chris Ridenour Dec 11 '12 at 08:51

2 Answers2

4

Found my own solution to this issue. The trick is to add the session_key from the django request object into the django-socketio message before you send it up to the server; then back on the server-side you can resolve the session_key back to a User object. Here is the code:

Template file: (served up by django server)

<input type="hidden" id="session_key" value="{{ request.session.session_key }}">
...
<script type="text/javascript" charset="utf-8">
    function someHandler(action, post_id, some_val){
        var data = {
            'action': action,
            'post_id': post_id,
            'value': some_val,
            'session_key': $("#session_key").val()
        };
        socket.send(data);
    }
</script>

events.py: (processed by django-socketio server)

from django.contrib.sessions.models import Session
from django.contrib.auth.models import User

def message(request, socket, context, message):
    session = Session.objects.get(session_key=message['session_key'])
    uid = session.get_decoded().get('_auth_user_id')
    user = User.objects.get(pk=uid)

Profit!

skandocious
  • 814
  • 9
  • 21
  • That would hit the database each and every on_message. Is that really necessary? **fixed** – Julius F Mar 06 '13 at 01:19
  • I suppose I could add the user object to the socket context and check that before hitting the database. Good point -- thanks. – skandocious Mar 06 '13 at 03:28
  • Just looked at your suggested code and unfortunately I think it completely missed the idea here. There is a never a case when it's okay for the user to NOT prove his identity to the socket server (ie, NOT sending a session_key). But it is possible, perhaps, to cache the user information in the socket context so it doesn't have to hit the DB on every message. I'll look into it later and edit my code if possible – skandocious Mar 06 '13 at 03:35
  • yep yesterday when I went to bed I went over it again and I came to the same conclusion, but the point of a system like socketio is to be not to heavy and hitting the database is kind of critical. Maybe using the session to something like cache or redis and only validate if the session key is valid and only fetch the user once in a while (cached) if the session key changed. – Julius F Mar 06 '13 at 10:52
0

To avoid the extra database hits in the answer by skandocious, Django's cached sessions can be used. This involves setting up memcached and modifying the SESSION_ENGINE setting to use the caching backend of your choice.

kontextify
  • 478
  • 5
  • 16