with vincent template register loginview custom and django django-authentication

vincent - ¿Cómo forzar al usuario a cerrar sesión en django?



register and login django (9)

Aunque la respuesta de Harold funciona en este caso específico, puedo ver al menos dos problemas importantes con ella:

  1. Esta solución solo se puede usar con un motor de sesión de base de datos. En otras situaciones (caché, archivo, cookie), el modelo de Session no se usaría.
  2. Cuando crece la cantidad de sesiones y usuarios en la base de datos, esto se vuelve bastante ineficiente.

Para resolver esos problemas, le sugiero que tome otro enfoque sobre el problema. La idea es almacenar en algún lugar la fecha en la que el usuario inició sesión en una sesión determinada y la última vez que solicitó que se cierre la sesión de un usuario.

Luego, cada vez que alguien acceda a su sitio, si la fecha de inicio de sesión es inferior a la fecha de cierre de sesión, puede cerrar la sesión forzosamente al usuario. Como dijo Dan, no existe una diferencia práctica entre cerrar la sesión de un usuario de inmediato o en su próxima solicitud a su sitio.

Ahora, veamos una posible implementación de esta solución para django 1.3b1 . En tres pasos:

1. almacenar en la sesión la última fecha de inicio de sesión

Afortunadamente, el sistema de autenticación Django expone una signal llamada user_logged_in . Solo tiene que registrar esas señales y guardar la fecha actual en la sesión. En la parte inferior de su models.py :

from django.contrib.auth.signals import user_logged_in from datetime import datetime def update_session_last_login(sender, user=user, request=request, **kwargs): if request: request.session[''LAST_LOGIN_DATE''] = datetime.now() user_logged_in.connect(update_session_last_login)

2. solicitar un cierre de sesión de fuerza para un usuario

Solo necesitamos agregar un campo y un método al modelo de User . Hay múltiples formas de lograr eso ( perfiles de usuario , herencia de modelos , etc.) cada uno con sus pros y sus contras.

En aras de la simplicidad, voy a usar la herencia del modelo aquí, si busca esta solución, no olvide escribir un servidor de autenticación personalizado .

from django.contrib.auth.models import User from django.db import models from datetime import datetime class MyUser(User): force_logout_date = models.DateTimeField(null=True, blank=True) def force_logout(self): self.force_logout_date = datetime.now() self.save()

Luego, si desea forzar la salida del usuario johndoe , solo tiene que:

from myapp.models import MyUser MyUser.objects.get(username=''johndoe'').force_logout()

3. implementar el control de acceso

La mejor manera aquí es usar un middleware como lo sugirió dan. Este middleware accederá a request.user , por lo que debe colocarlo después de ''django.contrib.auth.middleware.AuthenticationMiddleware'' en su configuración MIDDLEWARE_CLASSES .

from django.contrib.auth import logout class ForceLogoutMiddleware(object): def process_request(self, request): if request.user.is_authenticated() and request.user.force_logout_date and / request.session[''LAST_LOGIN_DATE''] < request.user.force_logout_date: logout(request)

Deberias hacer eso.

Notas

  • Tenga en cuenta la implicancia de rendimiento de almacenar un campo adicional para sus usuarios. Usar la herencia del modelo agregará un JOIN adicional. El uso de perfiles de usuario agregará una consulta adicional. Modificar directamente al User es la mejor manera de entender el rendimiento, pero sigue siendo un tema peliagudo .
  • Si implementa esa solución en un sitio existente, es probable que tenga problemas con las sesiones existentes, que no tendrán la clave ''LAST_LOGIN_DATE'' . Puede adaptar un poco el código de middleware para lidiar con ese caso:

    from django.contrib.auth import logout class ForceLogoutMiddleware(object): def process_request(self, request): if request.user.is_authenticated() and request.user.force_logout_date and / ( ''LAST_LOGIN_DATE'' not in request.session or / request.session[''LAST_LOGIN_DATE''] < request.user.force_logout_date ): logout(request)

  • En django 1.2.x, no hay señal de user_logged_in . Vuelva a anular la función de login :

    from django.contrib.auth import login as dj_login from datetime import datetime def login(request, user): dj_login(request, user) request.session[''LAST_LOGIN_DATE''] = datetime.now()

En mi aplicación django bajo ciertas condiciones, necesito poder forzar el cierre de sesión del usuario con un nombre de usuario. No necesariamente el usuario actual que está conectado, sino otro usuario. Entonces, el método de solicitud en mi opinión no tiene información de sesión sobre el usuario que quiero cerrar la sesión.

Estoy familiarizado con django.auth y con el método auth.logout, pero toma la solicitud como argumento. ¿Hay una "forma de django" para cerrar la sesión del usuario si todo lo que tengo es el nombre de usuario? ¿O tengo que rodar mi propio logout sql?


Como Tony Abou-Assaleh, también necesitaba desconectar a los usuarios que estaban inactivos, así que comencé implementando su solución. Después de un tiempo descubrí que el middleware está forzando una consulta DB en todas las solicitudes (para comprobar si el usuario fue bloqueado), y perjudica el rendimiento en páginas que no requieren inicio de sesión.

Tengo un objeto de usuario personalizado y Django> = 1.7, así que lo que terminé haciendo es anular su función get_session_auth_hash para invalidar la sesión cuando el usuario está inactivo. Una posible implementación es:

def get_session_auth_hash(self): if not self.is_active: return "inactive" return super(MyCustomUser, self).get_session_auth_hash()

Para que esto funcione, django.contrib.auth.middleware.SessionAuthenticationMiddleware debe estar en settings.MIDDLEWARE_CLASSES


Esto es en respuesta a la consulta de Balon:

Sí, con alrededor de 140k sesiones para repetir, puedo ver por qué la respuesta de Harold puede no ser tan rápida como te gustaría.

La forma en que recomendaría es agregar un modelo cuyas únicas dos propiedades son claves foráneas para los objetos User y Session . A continuación, agregue algún middleware que mantenga este modelo actualizado con las sesiones de usuario actuales. He usado este tipo de configuración antes; en mi caso, tomé prestado el módulo de sessionprofile de sesión de este sistema de inicio de sesión único para phpBB (consulte el código fuente en la carpeta "django / sessionprofile") y esto (creo) se ajustará a sus necesidades.

Lo que terminaría es alguna función de gestión en algún lugar de su código como este (suponiendo que los mismos nombres de código y el diseño que en el módulo de sessionprofile vinculado anteriormente):

from sessionprofile.models import SessionProfile from django.contrib.auth.models import User # Find all SessionProfile objects corresponding to a given username sessionProfiles = SessionProfile.objects.filter(user__username__exact=''johndoe'') # Delete all corresponding sessions [sp.session.delete() for sp in sessionProfiles]

(Creo que esto también eliminará los objetos SessionProfile , por lo que recuerdo, el comportamiento predeterminado de Django cuando se elimina un objeto al que se hace referencia mediante ForeignKey es ponerlo en cascada y también eliminar el objeto que contiene ForeignKey , pero si no es suficientemente trivial para borrar el contenido de sessionProfiles cuando hayas terminado.)


Incluso yo enfrenté este problema. Pocos spammers de India continúan publicando sobre Baba y Molvi para encontrar soluciones amorosas.

Lo que hice fue en el momento de la publicación solo inserté este código:

if request.user.is_active==False: return HttpResponse(''You are banned on the site for spaming.'')


Necesitaba algo similar en mi aplicación. En mi caso, si un usuario estaba configurado como inactivo, quería asegurarme de que si el usuario ya había iniciado sesión, se cerraría la sesión y no podría seguir utilizando el sitio. Después de leer esta publicación, llegué a la siguiente solución:

from django.contrib.auth import logout class ActiveUserMiddleware(object): def process_request(self, request): if not request.user.is_authenticated(): return if not request.user.is_active: logout(request)

Simplemente agregue este middleware en su configuración y listo. En el caso de cambiar las contraseñas, podría introducir un nuevo campo en el modelo de perfil de usuario que obligue al usuario a desconectarse, verificar el valor del campo en lugar de is_activo anterior y también desarmar el campo cuando un usuario inicie sesión. Esto último puede hacerse con la señal user_logged_in de Django.


No creo que haya una forma aprobada de hacer esto en Django todavía.

La identificación del usuario se almacena en el objeto de la sesión, pero está codificada. Desafortunadamente, eso significa que tendrás que repetir todas las sesiones, decodificar y comparar ...

Dos pasos:

Primero borre los objetos de sesión para su usuario objetivo. Si inician sesión desde varias computadoras, tendrán múltiples objetos de sesión.

from django.contrib.sessions.models import Session from django.contrib.auth.models import User # grab the user in question user = User.objects.get(username=''johndoe'') [s.delete() for s in Session.objects.all() if s.get_decoded().get(''_auth_user_id'') == user.id]

Luego, si es necesario, enciérrelos ...

user.is_active = False user.save()


Puede usar django-qsessions ( https://github.com/QueraTeam/django-qsessions ).

Es un back-end de sesión que extiende el back cached_db end cached_db de Django. Las sesiones tienen una clave externa para el usuario y también almacenan IP y agente de usuario.

Usando django-qsessions , puede cerrar la sesión de un usuario de manera fácil y eficiente:

user = User.objects.get(username=''abcd'') for session in user.session_set.all(): session.delete()


Tal vez, un poco de middleware que hace referencia a una lista de usuarios que se han visto obligados a cerrar la sesión. La próxima vez que el usuario intente hacer algo, finalícelos, redirigiéndolos, etc.

A menos, por supuesto, que necesiten desconectarse de inmediato. Pero, de nuevo, no lo notarían hasta que intentaran hacer una solicitud de todos modos, por lo que la solución anterior podría funcionar.


de django.contrib.sessions.models import Session

borrar sesión de usuario

[s.delete() for s in Session.objects.all() if s.get_decoded().get(''_auth_user_hash'') == user.get_session_auth_hash()]