我们的Django应用程序具有以下会话管理要求。
在阅读文档,Django代码和一些与此相关的博客文章后,我提出了以下实现方法。
要求1
通过将SESSION_EXPIRE_AT_BROWSER_CLOSE设置为True,可以轻松实现此要求。
要求2
我已经看到一些建议使用SESSION_COOKIE_AGE来设置会话到期时间。但这种方法存在以下问题。
即使用户正在使用该应用程序,会话也始终在SESSION_COOKIE_AGE结束时到期。 (这可以通过使用自定义中间件在每个请求上将会话到期设置为SESSION_COOKIE_AGE来防止,或者通过将SESSION_SAVE_EVERY_REQUEST设置为true来保存每个请求的会话。但是由于使用了SESSION_COOKIE_AGE,下一个问题是不可避免的。)
由于Cookie的工作方式,SESSION_EXPIRE_AT_BROWSER_CLOSE和SESSION_COOKIE_AGE是互斥的,即Cookie会在浏览器关闭时或在指定的到期时间到期。如果使用SESSION_COOKIE_AGE且用户在cookie过期之前关闭浏览器,则会保留cookie并重新打开浏览器将允许用户(或其他任何人)进入系统而无需重新进行身份验证。
Django仅依赖于存在的cookie来确定会话是否处于活动状态。它不会检查会话中存储的会话到期日期。
可以使用以下方法来实现此要求并解决上述问题。
要求3
当我们检测到会话已过期时(在上面的自定义SessionMiddleware中),在请求上设置一个属性以指示会话到期。此属性可用于向用户显示相应的消息。
要求4
使用JavaScript检测用户不活动,提供警告以及扩展会话的选项。如果用户希望扩展,请向服务器发送保持活动脉冲以延长会话。
要求5
使用JavaScript检测用户活动(在长期业务操作期间)并向服务器发送保持活动脉冲以防止会话过期。
上面的实现方法看起来非常复杂,我想知道是否有更简单的方法(特别是对于要求2)。
任何见解都将受到高度赞赏。
答案 0 :(得分:40)
这是一个想法......使用SESSION_EXPIRE_AT_BROWSER_CLOSE
设置在浏览器关闭时使会话暂停。然后在每个请求上设置会话中的时间戳。
request.session['last_activity'] = datetime.now()
并添加中间件以检测会话是否过期。这样的事情应该处理整个过程...
from datetime import datetime
from django.http import HttpResponseRedirect
class SessionExpiredMiddleware:
def process_request(request):
last_activity = request.session['last_activity']
now = datetime.now()
if (now - last_activity).minutes > 10:
# Do logout / expire session
# and then...
return HttpResponseRedirect("LOGIN_PAGE_URL")
if not request.is_ajax():
# don't set this for ajax requests or else your
# expired session checks will keep the session from
# expiring :)
request.session['last_activity'] = now
然后你只需要制作一些网址和视图,将相关数据返回到关于会话到期的ajax调用。
当用户选择“续订”会话时,可以这么说,您只需将requeset.session['last_activity']
设置为当前时间
显然,这段代码只是一个开始......但它应该让你走上正确的道路
答案 1 :(得分:26)
django-session-security就是这样......
...还有一项要求:如果服务器没有响应或攻击者断开了互联网连接:无论如何它都应该过期。
Disclamer:我维护这个应用程序。但我一直在观看这个帖子很长一段时间:))
答案 2 :(得分:22)
我只是使用Django的新手。
如果记录的用户关闭浏览器或处于空闲(不活动超时)一段时间,我想使会话过期。当我用谷歌搜索它时,这个SOF问题首先出现了。感谢很好的回答,我查找了资源,以了解Django中请求/响应周期中的中间件是如何工作的。这非常有帮助。
我正准备将自定义中间件应用到我的代码中,然后按照此处的最佳答案进行操作。但我仍然有点怀疑,因为这里的最佳答案是在2011年编辑的。我花了更多的时间从最近的搜索结果中搜索一下,并提出了简单的方法。
SESSION_EXPIRE_AT_BROWSER_CLOSE = True
SESSION_COOKIE_AGE = 10 # set just 10 seconds to test
SESSION_SAVE_EVERY_REQUEST = True
我没有检查其他浏览器而是Chrome。 1.即使设置了SESSION_COOKIE_AGE,我关闭浏览器时会话也已过期。 2.只有当我闲置超过10秒时,A会话才会过期。感谢SESSION_SAVE_EVERY_REQUEST,每当您发出新请求时,它会保存会话并更新超时到期
要更改此默认行为,请将SESSION_SAVE_EVERY_REQUEST设置为True。设置为True时,Django会在每次请求时将会话保存到数据库中。
请注意,会话cookie仅在创建或修改会话时发送。如果SESSION_SAVE_EVERY_REQUEST为True,则会在每次请求时发送会话cookie。
同样,每次发送会话cookie时,会话cookie的到期部分都会更新。
我只是留下答案,以便像我这样的Django中的一些新人不会花太多时间找到解决方案。
答案 3 :(得分:10)
满足第二个要求的一种简单方法是将settings.py中的SESSION_COOKIE_AGE值设置为适当的秒数。例如:
SESSION_COOKIE_AGE = 600 #10 minutes.
然而,仅通过这样做,会话将在10分钟后到期,无论用户是否展示某些活动。为了解决这个问题,每次用户使用以下句子执行任何类型的请求时,可以自动续订到期时间(另外10分钟):
request.session.set_expiry(request.session.get_expiry_age())
答案 4 :(得分:3)
你也可以使用 stackoverflow build in functions
SESSION_SAVE_EVERY_REQUEST = True
答案 5 :(得分:3)
在第一个请求中,您可以将会话到期时间设置为
self.request.session['access_key'] = access_key
self.request.session['access_token'] = access_token
self.request.session.set_expiry(set_age) #in seconds
使用access_key和令牌时,
try:
key = self.request.session['access_key']
except KeyError:
age = self.request.session.get_expiry_age()
if age > set_age:
#redirect to login page