如何查找特定用户的Django会话?

我正在写一个应用程序,我将从django和独立应用程序访问数据库。 两者都需要进行会话validation,会话应该相同。 Django有一个内置的身份validation/会话validation,这是我正在使用的,现在我需要弄清楚如何重用我的独立应用程序相同的会话。

我的问题是如何查找特定用户的session_key?

从它看起来没有任何关系auth_user和django_session

修改django_session表来添加一个明确的user_id可以使生活变得更容易。 假设你这样做(或者类似的),这里有四种方法可以根据你的喜好来改变事物:

分叉django.contrib.session代码。 我知道,我知道,这是一个可怕的build议。 但是它只有500行,包括所有的后端和减去testing。 破解相当简单。 只有当你要做一些重要的事情时,这才是最好的路线。

如果你不想分叉,你可以尝试连接到Session.post_save信号,并在那里。

或者你可以MonkeyPatch contrib.session.models.Session.save() 。 只需包装现有的方法(或创build一个新的方法),突破/合成你需要的任何值,将它们存储在新的字段中,然后super(Session, self).save()

还有一种方法是在settings.py文件中join2个(是的,两个)中间件类 – 一个在SessionMiddleware之前和之后。 这是因为中间件处理的方式。 SessionMiddleware之后列出的那个会在入站请求中获得一个请求,并且会话已经连接到它。 之前列出的可以对响应进行任何处理和/或更改/重新保存会话。

我们使用了最后一种技术的变体来为search引擎蜘蛛创build伪会话,使他们能够访问通常仅为会员的材料。 我们还检测来自相关search引擎的REFERER字段的入站链接,并且让用户完全访问那篇文章。

更新:

我的答案现在是相当古老的,但它仍然是最正确的。 请参阅下面的@ Gavin_Ballard更近的回答(9/29/2014),以解决此问题的另一种方法。

这个答案在原始问题发布5年后发布,但是当search这个问题的解决scheme时,这个SO线程是Google的最大search结果之一(它仍然是Django开箱即用的支持)。

我有一个替代的解决scheme,您只关心login的用户会话,它使用额外的UserSession模型将用户映射到他们的会话,如下所示:

 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) 

然后,只要用户login,就可以简单地保存一个新的UserSession实例:

 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) 

最后,当您想要列出(并可能清除)特定用户的会话时:

 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() 

这是它的坚果和螺栓,如果你想更多的细节,我有一个博客文章覆盖。

这样做有点棘手,因为不是每个会话都必须与经过身份validation的用户相关联; Django的会话框架也支持匿名会话,任何访问您的站点的人都将拥有一个会话,无论他们是否已经login。

由于会话对象本身是序列化的,因此Django无法知道你想要存储哪个数据,所以它只是将会话数据字典序列化为一个string(使用Python的标准“pickle”模块)并将其填充到数据库中。

如果您有会话密钥(将由用户的浏览器作为cookie值“sessionid”发送),获取数据最简单的方法就是使用该密钥查询会话表的会话,该会话将返回一个会话目的。 然后可以调用该对象的“get_decoded()”方法来获取会话数据字典。 如果您没有使用Django,可以查看源代码(django / contrib / sessions / models.py),以查看会话数据是如何反序列化的。

但是,如果您拥有用户标识,则需要遍历所有Session对象,对每个对象进行反序列化,然后查找具有名为“_auth_user_id”的键,并且该键的值为用户标识。

我发现这个代码片段

 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 

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

还没有validation,但看起来很直截了当。

彼得罗威尔,谢谢你的回应。 这是一个巨大的帮助。 这是我所做的工作。 只需要更改djang.contrib.sessions中的一个文件。

在django / contrib / sessions / models.py中,将user_id添加到表中(手动添加到数据库表或者删除表并运行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) 

现在在你的视图中你login(如果你使用django的基本login,你将不得不重写)

 # 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() 

这对我有效。

当我想推出一个垃圾邮件发送者时,我遇到了这个问题。 似乎将他们的账户设置为“不活跃”是不够的,因为他们仍然可以进入他们以前的会话。 那么 – 如何删除特定用户的会话,或者如何故意过期某个特定用户的会话?

答案是用户last_login字段来跟踪会话被禁用的时间,这告诉你expire_date是两周后,这可以让你在sessions表上执行一个有用的filter:

 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()