Ser*_*nko 51 authentication django session
我正在编写一个应用程序,我将从django和独立应用程序访问数据库.两者都需要进行会话验证,并且两者的会话应该相同.Django有一个内置的身份验证/会话验证,这就是我正在使用的,现在我需要弄清楚如何为我的独立应用程序重用相同的会话.
我的问题是如何查找特定用户的session_key?
从它的外观来看,没有任何东西将auth_user和django_session联系在一起
Gav*_*ard 45
这个答案是在原始问题发布五年之后发布的,但是这个SO线程是搜索此问题的解决方案时谷歌的最佳结果之一(并且它仍然是Django不支持的东西).
我有一个用例的备用解决方案,你只关心登录的用户会话,它使用一个额外的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)
Run Code Online (Sandbox Code Playgroud)
然后,您可以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)
Run Code Online (Sandbox Code Playgroud)
最后,当您想列出(并可能清除)特定用户的会话时:
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()
Run Code Online (Sandbox Code Playgroud)
这就是它的基本要点,如果你想了解更多细节,我会有一篇博文来介绍它.
Jam*_*ett 28
这有点棘手,因为并非每个会话都必须与经过身份验证的用户相关联; Django的会话框架也支持匿名会话,访问您网站的任何人都会有一个会话,无论他们是否已登录.
会话对象本身被序列化的事实使得这变得更加棘手 - 因为Django无法知道您想要存储哪些数据,它只是将会话数据字典序列化为字符串(使用Python的标准"pickle")模块)和填充到数据库中的东西.
如果你有会话密钥(将由用户的浏览器作为cookie值"sessionid"发送),获取数据的最简单方法就是在Session表中查询具有该密钥的会话,该密钥返回一个Session宾语.然后,您可以调用该对象的"get_decoded()"方法来获取会话数据的字典.如果您不使用Django,可以查看源代码(django/contrib/sessions/models.py)以查看会话数据的反序列化方式.
但是,如果您具有用户标识,则需要循环遍历所有Session对象,对每个对象进行反序列化并查找具有名为"_auth_user_id"的密钥的对象,并且该密钥的值为用户标识.
mic*_*ael 26
我找到了这段代码
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
Run Code Online (Sandbox Code Playgroud)
这里 http://scottbarnham.com/blog/2008/12/04/get-user-from-session-key-in-django/
尚未验证,但看起来很直接.
Pet*_*ell 24
修改django_session表以添加显式user_id可以使生活更轻松.假设你这样做(或类似的东西),这里有四种方法可以根据自己的喜好调整事物:
分叉django.contrib.session代码.我知道,我知道,这是一个可怕的建议.但它只有500行,包括所有后端和减去测试.破解非常简单.只有当你要做一些严肃的重新安排时,这才是最好的路线.
如果您不想分叉,可以尝试连接Session.post_save信号并在那里进行扫描.
或者你可以使用MonkeyPatch contrib.session.models.Session.save().只需包装现有方法(或创建一个新方法),分解/合成您需要的任何值,然后将它们存储在新字段中super(Session, self).save().
另一种方法是SessionMiddleware在你的settings.py文件中放入2个(是的,两个)中间件类 - 一个在之前和之后一个.这是因为中间件的处理方式.之后列出的那个SessionMiddleware将在入站请求中获得已附加会话的请求.之前列出的那个可以对响应进行任何处理和/或更改/重新保存会话.
我们使用最后一种技术的变体来为搜索引擎蜘蛛创建伪会话,以便为他们提供对通常仅限成员的材料的特殊访问.我们还检测REFERER字段来自关联搜索引擎的入站链接,并且我们为用户提供对该文章的完全访问权限.
更新:
我的答案现在相当古老,尽管它仍然是正确的.有关此问题的另一种方法,请参阅下面的@ Gavin_Ballard最近的答案(2014年9月29日).
小智 7
彼得罗威尔,谢谢你的回应.这是一个巨大的帮助.这就是我为了让它发挥作用所做的.只需要在djang.contrib.sessions中更改一个文件.
在django/contrib/sessions/models.py中,将user_id添加到表中(手动添加到DB表或删除表并运行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)
Run Code Online (Sandbox Code Playgroud)
现在在您查看登录的位置(如果使用django的基本登录,则必须覆盖它)
# 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()
Run Code Online (Sandbox Code Playgroud)
这对我有用.
当我想要发垃圾邮件时,我遇到了这个问题.似乎将他们的帐户设置为"不活动"是不够的,因为他们仍然可以进入他们之前的会话.那么 - 如何删除特定用户的会话,或者如何故意使特定用户的会话失效?
答案是使用该last_login字段来跟踪会话被禁用的时间,这会告诉您expire_date两周之后,这会让您在会话表上执行有用的过滤器:
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()
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
31775 次 |
| 最近记录: |