如何由于 Django 中的不活动而使会话过期?
Posted
技术标签:
【中文标题】如何由于 Django 中的不活动而使会话过期?【英文标题】:How to expire session due to inactivity in Django? 【发布时间】:2011-03-02 17:39:48 【问题描述】:我们的 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 来确定会话是否处于活动状态。它不会检查与会话一起存储的会话到期日期。
以下方法可用于实现此要求并解决上述问题。
不要设置 SESSION_COOKIE_AGE。 在每个请求上将会话的到期日期设置为“当前时间 + 非活动期”。 覆盖 SessionMiddleware 中的 process_request 并检查会话是否过期。如果会话已过期,则丢弃会话。要求 3 当我们检测到会话已经过期时(在上面的自定义 SessionMiddleware 中),在请求上设置一个属性来指示会话过期。此属性可用于向用户显示适当的消息。
要求 4 使用 javascript 检测用户不活动,提供警告以及延长会话的选项。如果用户希望延长会话,请向服务器发送保活脉冲以延长会话。
要求 5 使用 JavaScript 检测用户活动(在长时间的业务操作期间)并向服务器发送保持活动脉冲以防止会话过期。
上面的实现方法看起来很复杂,我想知道是否有更简单的方法(特别是对于要求 2)。
任何见解都将受到高度赞赏。
【问题讨论】:
+1 提供详细的解决方案 有一个中间件可以满足你的需要。 on github 和 on pypi "由于 cookie 的工作方式,SESSION_EXPIRE_AT_BROWSER_CLOSE 和 SESSION_COOKIE_AGE 是互斥的,即 cookie 在浏览器关闭或指定的到期时间到期。如果使用 SESSION_COOKIE_AGE 并且用户在 cookie 之前关闭浏览器过期,cookie 被保留,重新打开浏览器将允许用户(或任何其他人)进入系统,而无需重新验证。”如果我错了,请纠正我,但在较新的 Django 版本中,这似乎不再适用? (至少 1.5+) "Django 仅依靠存在的 cookie 来确定会话是否处于活动状态。它不会检查与会话一起存储的会话到期日期。"这是not true了。 2020年,第二个答案应该是公认的。当前接受的一个增加了已经在 Django 上实现的东西的复杂性。 【参考方案1】:我刚开始使用 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,我没有检查其他浏览器。
-
即使设置了 SESSION_COOKIE_AGE,当我关闭浏览器时会话也会过期。
只有当我空闲超过 10 秒时,会话才过期。感谢 SESSION_SAVE_EVERY_REQUEST,每当您发生新请求时,它都会保存会话并更新超时以过期
要更改此默认行为,请将 SESSION_SAVE_EVERY_REQUEST 设置设置为 True。当设置为 True 时,Django 将在每次请求时将会话保存到数据库中。
请注意,会话 cookie 仅在创建或修改会话时发送。如果 SESSION_SAVE_EVERY_REQUEST 为 True,会话 cookie 将在每个请求上发送。
同样,会话 cookie 的过期部分在每次发送会话 cookie 时都会更新。
django manual 1.10
我只是留下答案,这样一些像我这样的 Django 新手就不会像我一样花太多时间来寻找解决方案。
【讨论】:
【参考方案2】:这是一个想法...使用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
然后,您只需创建一些 url 和视图,即可将有关会话到期的相关数据返回给 ajax 调用。
当用户选择“更新”会话时,可以这么说,您所要做的就是再次将requeset.session['last_activity']
设置为当前时间
显然这段代码只是一个开始......但它应该让你走上正确的道路
【讨论】:
我只是对此持怀疑态度,但我不认为if not request.is_ajax()
是完全安全的。持有会话到期前欺骗/发送 ajax 调用并保持会话继续进行的人不能吗?
@notbad.jpeg:一般来说,“活动”很容易被欺骗。掌握会话并继续发送请求的人处于活动状态。
这是一个很好的答案。中间件是 Django 开发中一个未被充分利用的工具。【参考方案3】:
django-session-security 就是这样做的...
...还有一个额外的要求:如果服务器没有响应或攻击者断开了互联网连接:无论如何它都应该过期。
免责声明:我维护这个应用程序。但是我一直在看这个帖子很长很长的时间:)
【讨论】:
很酷的应用程序 - 设计精美,制作精良。不错,干净的代码...谢谢。 如果用户在离开时关闭浏览器或标签页(未注销),是否仍会强制用户注销?它可以处理这种情况吗? 那将由纯http会话cookie到期处理,不是吗?【参考方案4】:满足您的第二个要求的一种简单方法是将 settings.py 中的 SESSION_COOKIE_AGE 值设置为合适的秒数。例如:
SESSION_COOKIE_AGE = 600 #10 minutes.
但是,无论用户是否表现出某些活动,只要执行此操作,会话就会在 10 分钟后过期。为了解决这个问题,每次用户执行任何类型的请求时,都可以自动更新过期时间(再延长 10 分钟),使用以下语句:
request.session.set_expiry(request.session.get_expiry_age())
【讨论】:
SESSION_COOKIE_AGE = 600 这将随着每个新页面请求或页面刷新而延长会话年龄 我确认只要设置SESSION_COOKIE_AGE
就足够了,任何请求(发送会话cookie)都会自动刷新会话cookie过期时间。【参考方案5】:
你也可以使用 *** build in functions
SESSION_SAVE_EVERY_REQUEST = True
【讨论】:
完全不相关 - 这是为了在每个请求上强制 session 保存(不是“会话 cookie 刷新”),而不检查会话是否已被修改。【参考方案6】:在第一个请求中,您可以将会话到期设置为
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和token时,
try:
key = self.request.session['access_key']
except KeyError:
age = self.request.session.get_expiry_age()
if age > set_age:
#redirect to login page
【讨论】:
【参考方案7】:我正在使用 Django 3.2,我建议使用 django-auto-logout 包。
它允许活动时间和空闲时间会话控制。
在模板中,您可以将变量与 Javascript 一起使用。
【讨论】:
虽然此链接可能会回答问题,但最好在此处包含答案的基本部分并提供链接以供参考。如果链接页面发生更改,仅链接答案可能会失效。 - From Review以上是关于如何由于 Django 中的不活动而使会话过期?的主要内容,如果未能解决你的问题,请参考以下文章