2008-10-25 13 views
45

Estoy escribiendo una aplicación en la que accederé a la base de datos desde django y desde una aplicación independiente. Ambos necesitan hacer la verificación de la sesión y la sesión debería ser la misma para ambos. Django tiene una autentificación/verificación de sesión incorporada, que es lo que estoy usando, ahora necesito descubrir cómo reutilizar la misma sesión para mi aplicación independiente.¿Cómo buscar la sesión de django para un usuario en particular?

Mi pregunta es ¿cómo puedo buscar una session_key para un usuario en particular?

Por lo que se ve no hay nada que une auth_user y django_session

Respuesta

23

Modificar la tabla django_session para agregar un user_id explícito puede hacer la vida mucho más fácil. Suponiendo que hace eso (o algo similar), aquí hay cuatro enfoques para abatir cosas a su gusto:

Tenedor el código django.contrib.session. Lo sé, lo sé, es algo horrible de sugerir. Pero solo son 500 líneas, incluidos todos los back-end y menos las pruebas. Es bastante fácil de hackear. Esta es la mejor ruta solo si vas a hacer una reorganización seria de las cosas.

Si no desea realizar un fork, intente conectarse a la señal Session.post_save y transmita allí.

O podría MonkeyPatch contrib.session.models.Session.save(). Simplemente ajuste el método existente (o cree uno nuevo), desglose/sintetice los valores que necesite, almacénelos en sus nuevos campos y luego super(Session, self).save().

Sin embargo, otra manera de hacer esto es poner en 2 (sí, dos) clases de middleware - uno antes y otro después de SessionMiddleware en su settings.py archivo. Esto se debe a la forma en que se procesa el middleware. El que aparece después de SessionMiddleware recibirá, en la solicitud de entrada, una solicitud con la sesión ya asociada. El que se mencionó anteriormente puede hacer cualquier procesamiento en la respuesta y/o cambiar/volver a guardar la sesión.

Utilizamos una variación de esta última técnica para crear pseudo-sesiones para las arañas de los motores de búsqueda para darles acceso especial al material que normalmente es solo para miembros.También detectamos enlaces entrantes donde el campo REFERER es del motor de búsqueda asociado y le damos acceso total al usuario a ese artículo.

Actualización:

Mi respuesta es ahora bastante antiguo, aunque todavía se encuentra en su mayoría correcto. Vea la respuesta mucho más reciente de @Gavin_Ballard (9/29/2014) a continuación para otro acercamiento a este problema.

+0

Hacer esto puede romper las pruebas si lo hace sin forzar el código django. Si la aplicación de sesiones está en INSTALLED_APPS, la tabla de sesiones se creará dos veces y se cancelarán las pruebas. No estoy seguro de si es seguro eliminar la aplicación de sesión django si proporcionó su propia tabla django_session. –

+2

Las sesiones de usuario de Django ahora están disponibles para darle esta funcionalidad: https://github.com/Bouke/django-user-sessions – sww314

+0

@ sww314 - Hice un escaneo rápido del proyecto GitHub vinculado, y parece una opción muy razonable acercamiento al problema ¡Gracias! –

28

Esto es algo difícil de hacer, porque no todas las sesiones se asocia necesariamente con un usuario autenticado; El marco de sesiones de Django también admite sesiones anónimas, y cualquiera que visite su sitio tendrá una sesión, independientemente de si están o no registradas.

Esto se complica aún más por el hecho de que el objeto de sesión en sí mismo está serializado. dado que Django no tiene forma de saber qué datos exactamente desea almacenar, simplemente serializa el diccionario de datos de sesión en una cadena (usando el módulo "pickle" estándar de Python) y lo incluye en su base de datos.

Si tiene la clave de sesión (que será enviada por el navegador del usuario como el valor de la cookie "sessionid"), la forma más fácil de obtener los datos es simplemente consultar la tabla de Sesión con esa clave, que devuelve un objeto Session. A continuación, puede llamar al método "get_decoded()" de ese objeto para obtener el diccionario de datos de la sesión. Si no está utilizando Django, puede consultar el código fuente (django/contrib/sessions/models.py) para ver cómo se deserializan los datos de la sesión.

Si tiene la identificación de usuario, sin embargo, tendrá que recorrer todos los objetos de sesión, deserializar cada uno y buscar uno que tenga una clave llamada "_auth_user_id" y para la cual el valor de esa clave es la identificación del usuario

+0

y por qué no adjuntó la sesión a un usuario en un middleware, y no a la solicitud como en la versión incorporada? – aRkadeFR

6

Peter Rowell, gracias por su respuesta. Fue una gran ayuda. Esto es lo que hice para que funcione. Solo tuvo que cambiar un archivo en djang.contrib.sessions.

En django/contrib/sessions/models.py, agregue el user_id a la tabla (agregue manualmente a la tabla DB o elimine la tabla y ejecute manage.py syncdb).

class Session(models.Model): 

    ... 

    user_id = models.IntegerField(_('user_id'), null=True) 

    ... 

    def save(self, *args, **kwargs): 
     user_id = self.get_decoded().get('_auth_user_id') 
     if (user_id != None): 
      self.user_id = user_id 

     # Call the "real" save() method. 
     super(Session, self).save(*args, **kwargs) 

En su vista en la que haces de inicio de sesión (si se utiliza inicio de sesión de base de Django, tendrá que anularla)

# On login, destroy all prev sessions 
     # This disallows multiple logins from different browsers 
     dbSessions = Session.objects.filter(user_id = request.user.id) 
     for index, dbSession in enumerate(dbSessions): 
      if (dbSession.session_key != request.session.session_key): 
       dbSession.delete() 

Esto funcionó para mí.

23

me encontré con este fragmento de código

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

session_key = '8cae76c505f15432b48c8292a7dd0e54' 

session = Session.objects.get(session_key=session_key) 
uid = session.get_decoded().get('_auth_user_id') 
user = User.objects.get(pk=uid) 

print user.username, user.get_full_name(), user.email 

aquí http://scottbarnham.com/blog/2008/12/04/get-user-from-session-key-in-django/

no ha comprobado todavía, pero se ve bastante sencillo.

+5

Directo, pero la operación inversa. Obtener la clave de la identificación del usuario (sin modificar los modelos) requiere iterar sobre cada sesión. – kibibu

4

Me encontré con este problema cuando quería expulsar a un spammer. Parece que establecer su cuenta en "inactivo" no es suficiente, porque aún pueden aparecer en su sesión anterior. Entonces, ¿cómo eliminar una sesión para un usuario específico o cómo expirar deliberadamente una sesión para un usuario específico?

La respuesta es que el usuario del campo last_login para determinar la hora a la que la sesión ha sido desactivado, lo que indica que el expire_date es dos semanas más tarde, lo que le permite realizar un filtro útil en la tabla de sesiones:

from django.contrib.sessions.models import Session 
from django.contrib.auth.models import User 
from datetime import datetime 
from dateutil.relativedelta import relativedelta 

baduser = User.objects.get(username="whoever")  
two_weeks = relativedelta(weeks=2) 
two_hours = relativedelta(hours=2) 
expiry = baduser.last_login + two_weeks 
sessions = Session.objects.filter(
    expire_date__gt=expiry - two_hours, 
    expire_date__lt=expiry + two_hours 
) 
print sessions.count() # hopefully a manageable number 

for s in sessions: 
    if s.get_decoded().get('_auth_user_id') == baduser.id: 
     print(s) 
     s.delete() 
+1

¡Hacky pero efectivo, me encanta! Lamentablemente, creo que esto no funciona cuando el back-end de la sesión es redis en lugar de DB. –

38

Esta respuesta se publica cinco años después de la pregunta original, pero este hilo SO es uno de los principales resultados de Google al buscar una solución a este problema (y sigue siendo algo que no se admite de manera inmediata Django).

Tengo una solución alternativa para el caso de uso donde estás sólo se ocupa de iniciar sesión en las sesiones de usuario, que utiliza un modelo adicional UserSession para asignar usuarios a sus sesiones, algo como esto:

from django.conf import settings 
from django.db import models 
from django.contrib.sessions.models import Session 

class UserSession(models.Model): 
    user = models.ForeignKey(settings.AUTH_USER_MODEL) 
    session = models.ForeignKey(Session) 

a continuación, puede guardar una nueva instancia UserSession cualquier momento un usuario se conecta:

from django.contrib.auth.signals import user_logged_in 

def user_logged_in_handler(sender, request, user, **kwargs): 
    UserSession.objects.get_or_create(user = user, session_id = request.session.session_key) 

user_logged_in.connect(user_logged_in_handler) 

y finalmente cuando desea la lista (y, potencialmente, claro) las sesiones para un usuario en particular:

from .models import UserSession 

def delete_user_sessions(user): 
    user_sessions = UserSession.objects.filter(user = user) 
    for user_session in user_sessions: 
     user_session.session.delete() 

Esa es la tuerca y pernos de la misma, si desea obtener más detalles tengo un blog post cubriéndolo.

+2

El problema que estoy teniendo es que la sesión no se guarda necesariamente cuando se activa 'user_logged_in', y así obtener un error de restricción FK. ¿Es seguro ejecutar 'request.session.save()' en 'user_logged_in_handler()' primero? Alternativamente, podría cambiar el campo FK a texto, pero eso significa que probablemente necesite hacer una limpieza extra. – DanH

+0

Pregunta complementaria: ¿Qué sucede si quiero realizar un seguimiento de los inicios de sesión del usuario? Al eliminar la sesión, perdería eso. ¿Cómo puedo invalidar la sesión sin eliminarla? – alfetopito

+1

@DanH No he visto ese problema; en lugar de llamar a 'request.session.save()' Creo que iría con tu segunda opción y evitaré usar un FK. La única limpieza adicional que tendría que hacer es llamar a 'user_session.delete()' después de 'user_session.session.delete()'. (En este ejemplo, tendría que agregar un método 'session()' a su modelo 'UserSession' para buscar la sesión correcta.) –

Cuestiones relacionadas