with setup mod_wsgi httpd how conf and python django apache2 mod-wsgi django-authentication

python - setup - Permitiendo solo una sesión activa por usuario en la aplicación Django



django wsgi (3)

Quiero restringir a los usuarios registrados para que solo tengan una sesión activa, es decir, si el usuario inicia sesión con un nuevo ID de sesión, la sesión anterior debe terminar. Ya encontré mucha ayuda en SO: here y here

Implementé la solución de middleware, con un poco de comprobación adicional ...

class OnlyOneUserMiddleware(object): """ Middleware to ensure that a logged-in user only has one session active. Will kick out any previous session. """ def process_request(self, request): if request.user.is_authenticated(): try: cur_session_key = request.user.get_profile().session_key if cur_session_key and cur_session_key != request.session.session_key: # Default handling... kick the old session... Session.objects.get(session_key=cur_session_key).delete() if not cur_session_key or cur_session_key != request.session.session_key: p = request.user.get_profile() p.session_key = request.session.session_key p.save() except ObjectDoesNotExist: pass

Hasta ahora, todo bien ... en el servidor de desarrollo Django (manage.py runserver) todo funciona correctamente, da inicio a la sesión anterior ...

... pero cuando se usa Apache (con mod_wsgi), ¡no funciona!

He intentado encontrar alguna información sobre esto, pero hasta ahora no he tenido suerte ...

Lo más cercano que he encontrado es this , pero es una especie de problema "opuesto" ...

Cualquier ayuda sería muy apreciada.

Edición: agregué una impresión de depuración antes de eliminar la sesión ... aquí hay un fragmento del error.log de Apache:

[Fri Jan 20 09:56:50 2012] [error] old key = f42885ccb7f33b6afcb2c18fca14f44a [Fri Jan 20 09:56:50 2012] [error] new key = ce4cfb672e6025edb8ffcd0cf2b4b8d1 [Fri Jan 20 09:57:14 2012] [error] old key = f42885ccb7f33b6afcb2c18fca14f44a [Fri Jan 20 09:57:14 2012] [error] new key = 0815c56241ac21cf4b14b326f0aa7e24

Las dos primeras mentiras son de cuando entré con la primera sesión (Firefox)

los dos últimos son de cuando entré con la segunda sesión (Chromium)

... resulta que el registro de sesión anterior no se borra ... ???

Estoy ejecutando frente a la misma instancia de PostgreSQL que hice con el servidor dev ...

Edit2: Resultó que mi código estaba defectuoso ... falló cuando no se encontró la nueva Session_key en Session ...

Aquí está el código fijo ... el intento ... excepto ahora está en el lugar correcto

class OnlyOneUserMiddleware(object): """ Middleware to ensure that a logged-in user only has one session active. Will kick out any previous session. """ def process_request(self, request): if request.user.is_authenticated(): cur_session_key = request.user.get_profile().session_key if cur_session_key and cur_session_key != request.session.session_key: # Default handling... kick the old session... try: s = Session.objects.get(session_key=cur_session_key) s.delete() except ObjectDoesNotExist: pass if not cur_session_key or cur_session_key != request.session.session_key: p = request.user.get_profile() p.session_key = request.session.session_key p.save()


De hecho, hay muchas preguntas similares por todas partes, pero aquí está mi solución.

Cuando un usuario inicia sesión todas las sesiones activas y elimina las que tienen el mismo user.id Para sitios web más pequeños, esto debería hacer muy bien.

# __init__.py # Logs user out from all other sessions on login, django 1.8 from django.contrib.sessions.models import Session from django.contrib.auth.signals import user_logged_in from django.db.models import Q from django.utils import timezone def limit_sessions(sender, user, request, **kwargs): # this will be slow for sites with LOTS of active users for session in Session.objects.filter( ~Q(session_key = request.session.session_key), expire_date__gte = timezone.now() ): data = session.get_decoded() if data.get(''_auth_user_id'', None) == str(user.id): # found duplicate session, expire it session.expire_date = timezone.now() session.save() return user_logged_in.connect(limit_sessions)


Siempre se puede utilizar este enfoque, aunque no se recomienda, funciona.

my_old_sessions = Session.objects.all() for row in my_old_sessions: if row.get_decoded().get("_username") == request.user.username: row.delete()

Debería implementar el código anterior en su función de inicio de sesión () justo antes de autenticar al usuario.

Por supuesto, esto solo funciona si tiene un método de función de inicio de sesión () que almacena el nombre de usuario de los USUARIOS en su sesión de la siguiente manera:

request.session["_username"] = request.user.username

Si utiliza este enfoque, recuerde vaciar su base de datos de todas sus sesiones antes de ejecutar su servidor después de haber realizado estos cambios porque generará errores de KeyLookUp.


Siento que, de alguna manera, las señales de django.contrib.auth podrían ayudar aquí. Al iniciar sesión, invalide las sesiones de usuario anteriores.