2010-06-11 94 views
72

我们的Django应用程序具有以下会话管理要求。由于在Django中处于非活动状态,如何过期会话?

  1. 当用户关闭浏览器时会话过期。
  2. 会话在一段时间不活动后过期。
  3. 检测会话何时因不活动而到期并向用户显示适当的消息。
  4. 在闲置期结束前几分钟向即将到期的会话过期的用户发出警告。随着警告,为用户提供延长会话的选项。
  5. 如果用户正在处理应用程序中不涉及向服务器发送的请求的长时间业务活动,则该会话不得超时。

在阅读文档,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来确定会话是否处于活动状态。它不会检查与会话一起存储的会话过期日期。

以下方法可用于实现此要求并解决上述问题。

  • 请勿设置SESSION_COOKIE_AGE。
  • 将会话的终止日期设置为每个请求的“当前时间+非活动时间段”。
  • 在SessionMiddleware中覆盖process_request并检查会话过期。如果会话已过期,请放弃该会话。

要求3
当我们检测到会话已过期(在上面的定制SessionMiddleware),该请求的属性集,以指示会话终结。该属性可用于向用户显示适当的消息。

要求4
使用JavaScript来检测用户的活动,提供警告并延长会话的选项。如果用户希望扩展,则向服务器发送保活脉冲以延长会话。

要求5
使用JavaScript来检测用户活动(长期的业务运营中),并发送永葆脉冲到服务器,以防止过期会话。


上面的实现方法看起来非常复杂,我想知道是否有更简单的方法(特别是对于需求2)。

任何见解将不胜感激。

+1

+1用于提供详细的解决方案 – Don 2012-06-07 15:55:52

+1

“由于Cookie的工作方式,SESSION_EXPIRE_AT_BROWSER_CLOSE和SESSION_COOKIE_AGE是互斥的,即cookie在到浏览器关闭时或在指定的到期时间到期,如果使用SESSION_COOKIE_AGE且用户关闭浏览器在cookie过期之前,Cookie将被保留,并且重新打开浏览器将允许用户(或任何其他人)进入系统而不需要重新进行身份验证。“纠正我,如果我错了,但在新的Django版本中,这似乎不再是真的吗? (至少1.5+) – 2014-11-04 12:53:26

+0

有一个中间件可以做你需要的东西。 [在github上](https://github.com/subhranath/django-session-idle-timeout)和[在pypi上](http://pypi.python.org/pypi/django-session-idle-timeout/1.3 .1) – gbutler 2013-02-12 22:50:32

回答

38

这是一个想法...在浏览器上关闭会话并使其与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']再次当前时间

显然,这种代码仅仅是一个开始......但它应该得到你在正确的道路

+0

我只是在怀疑这里,但我不认为'如果不request.is_ajax()'是完全安全的。不能得到持有该会话预先到期欺骗/发送ajax调用,并保持会话进行? – 2013-05-11 03:53:51

+2

@ notbad.jpeg:一般来说,“活动”很容易被欺骗。持有该会话并不断发送请求的人只是活跃的。 – RemcoGerlich 2014-08-15 07:38:00

+0

这是一个很好的答案。中间件是Django开发中一个未充分利用的工具。 – 2016-04-26 13:57:51

25

django-session-security上做到了这一点......

...有一个额外的要求:如果服务器不响应或者攻击者断开互联网连接:应该反正过期。

Disclamer:我维护这个程序。但我一直在看这个线程一个很长很长的时间:)

+1

很酷的应用程序 - 很好的设计和精心打造。很好,干净的代码...谢谢。 – nicorellius 2014-03-01 17:33:19

+1

也定期更新 - 谢谢jpic – datakid 2014-03-13 01:54:14

+0

如果用户在他/她离开时关闭浏览器或选项卡(不注销),是否仍强制用户注销?它处理这种情况吗? – waterkinq 2016-04-05 11:40:01

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 
+0

向上投票赞成缺乏评论downvoter。 – Ruraj 2016-02-26 12:52:47

9

满足您的第二个要求的一个简单方法是在设置中设置SESSION_COOKIE_AGE值。py到合适的秒数。例如:

SESSION_COOKIE_AGE = 600  #10 minutes. 

但是,仅通过执行此操作,会话将在10分钟后过期,无论用户是否展示某些活动。为了解决这个问题,到期时间可以自动更新(再额外10分钟),每次使用者用下面的句子任何种类的要求:

request.session.set_expiry(request.session.get_expiry_age()) 
8

我只是非常新的使用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 

我没有检查其他浏览器,但铬。 1.即使设置了SESSION_COOKIE_AGE,关闭浏览器时会话过期。 2.仅当我闲置超过10秒时,会话过期。感谢SESSION_SAVE_EVERY_REQUEST,每当您发生新的请求时,它都会将会话和更新超时保存到期。

要更改此默认行为,请将SESSION_SAVE_EVERY_REQUEST设置设置为True。当设置为True时,Django会在每个请求中将会话保存到数据库。

请注意,会话cookie仅在创建或修改会话时发送。如果SESSION_SAVE_EVERY_REQUEST为真,会话cookie将在每个请求中发送。

同样,每次发送会话cookie时会更新会话cookie的部分。

django manual 1.10

我刚刚离开的回答使一些人谁是一种新的在Django像我不会花太多时间去找出解决办法的一种方式我做到了。

+0

你是男人!感谢您的研究。 – 2017-08-11 07:49:39

相关问题