如何在 5 分钟内使 Django 会话过期?

Posted

技术标签:

【中文标题】如何在 5 分钟内使 Django 会话过期?【英文标题】:How to expire Django session in 5minutes? 【发布时间】:2013-01-27 15:33:40 【问题描述】:

我正在使用它来登录用户:

def login_backend(request):
    if request.method == 'POST':
        username = request.POST['username']
        password = request.POST['password']
        user = authenticate(username=username, password=password)
        if user is not None:
            login(request, user)
            request.session.set_expiry(300)
            return HttpResponseRedirect('/overview/')
        else:
            return HttpResponseRedirect('/login_backend/')
    else:
        return render_to_response('login_backend.html', context_instance=RequestContext(request))

我希望会话在 5 分钟后过期,因此我在上面的视图中添加了 request.session.set_expiry(300)。但是会话永远不会过期。我做错了什么?

【问题讨论】:

我已经回答了同样的问题,这里是链接***.com/questions/14808238/…。如果您有任何澄清,请告诉我 如果用户正在打开应用程序,我不希望会话过期。如果用户 5 分钟没有打开应用程序,我希望会话过期。 是的,没错,这就是我的答案。如果用户空闲,它将自动注销。你想让我在这里发布整个答案吗? 是的,这样做。到时候我会把你的答案标记为正确的。 【参考方案1】:

有两个参数可以使会话过期,SESSION_EXPIRE_AT_BROWSER_CLOSE 和 SESSION_COOKIE_AGE。 如果您想在 5 分钟内过期,您的设置应如下所示:

SESSION_EXPIRE_AT_BROWSER_CLOSE = False
SESSION_COOKIE_AGE = 5 * 60 #

将两者结合起来,了解如何编写自定义中间件"Is there a way to combine behavior of SESSION_EXPIRE_AT_BROWSER_CLOSE and SESSION_COOKIE_AGE"

【讨论】:

如果用户正在打开应用程序,我不希望会话过期。如果用户 5 分钟没有打开应用程序,我希望会话过期。 请注意,我的中间件代码检查 request.user.is_authenticated()。【参考方案2】:

根据您的项目,这可能还不够。

例如,如果用户花费 6 分钟填写表单并点击“保存”会怎样?浏览器将被重定向到登录页面,表单数据将丢失。

此外,如果用户在打开的浏览器页面中带着机密数据离开工作站,也会存在潜在的安全问题。

另外,如果用户在 6 分钟内阅读了一个页面怎么办?那么在没有警告或任何方式延长他的会话的情况下将他注销并不是很酷......

考虑到这些问题,您可能会发现django-session-security 很有用。

【讨论】:

试用了 django-session-security。轻而易举地安装,像魅力一样工作。感谢您制作了如此精彩的模块! 这个包在我使用 Django 2.2 时效果很好。对文档中提供的说明进行了一些必要的调整,因为它是为 Django pre-1.10 编写的: - session_security.middleware.SessionSecurityMiddleware 被添加到 MIDDLEWARE 列表中,而不是 MIDDLEWARE_CLASSES 不再存在 - 它是 @ 987654325@ 而不是"django.core.context_processors.request" 必须添加到"OPTIONS""OPTIONS" 下的"context_processors" 列表中TEMPLATES【参考方案3】:

Django 1.6 更新

由于 json 可序列化,下面的中间件代码在 Django 1.6 及以上版本中不起作用。要使其在所有版本的 Django 中都能正常工作,请放置会话序列化程序。

settings.py

#Handle session is not Json Serializable
SESSION_SERIALIZER = 'django.contrib.sessions.serializers.PickleSerializer'

上面的序列化程序示例适用于 Django 1.6。请搜索其他版本。谢谢...

创建middleware.py

from datetime import datetime, timedelta
from django.conf import settings
from django.contrib import auth


class AutoLogout:
  def process_request(self, request):
    if not request.user.is_authenticated() :
      #Can't log out if not logged in
      return

    try:
      if datetime.now() - request.session['last_touch'] > timedelta( 0, settings.AUTO_LOGOUT_DELAY * 60, 0):
        auth.logout(request)
        del request.session['last_touch']
        return
    except KeyError:
      pass

    request.session['last_touch'] = datetime.now()

更新您的 settings.py

MIDDLEWARE_CLASSES = [
    .........................

    'app_name.middleware.AutoLogout', 
]

# Auto logout delay in minutes
AUTO_LOGOUT_DELAY = 5 #equivalent to 5 minutes

【讨论】:

@hec 如果您将会话序列化程序的设置用于修复<object> is not json serializable,它将起作用 或者您可以将 datetime.now() 更改为 time.time()。对条件逻辑进行其他小的相关更改,它适用于 JSON 序列化程序。 @Hec 也可以。会话序列化程序不仅适用于日期时间。谢谢... :) @catherine,为什么您的代码与我在my answer 中链接的代码不同,它是在您的一年前编写的? PickleSerializer 太棒了! (Django 1.8 - 相同的路径)【参考方案4】:

在调用 login() 之前设置会话时间!

...
request.session.set_expiry(300)
login(request, user)
...     

【讨论】:

【参考方案5】:

这对我有用

settings.py

TIME= 240*60  //four hours  or your time
SESSION_SERIALIZER = 'django.contrib.sessions.serializers.PickleSerializer'
SESSION_EXPIRE_AT_BROWSER_CLOSE= True
SESSION_COOKIE_AGE = TIME    //change expired session
SESSION_IDLE_TIMEOUT = TIME  //logout

中间件.py

from django.contrib.auth import logout
from django.contrib import messages
import datetime
from django.shortcuts import redirect

import settings

class SessionIdleTimeout:
    def process_request(self, request):
        if request.user.is_authenticated():
            current_datetime = datetime.datetime.now()
            if ('last_login' in request.session):
                last = (current_datetime - request.session['last_login']).seconds
                if last > settings.SESSION_IDLE_TIMEOUT:
                    logout(request, login.html)
            else:
                request.session['last_login'] = current_datetime
        return None

【讨论】:

【参考方案6】:

Django 1.9

编辑您的 settings.py 并添加以下内容:

# SESSION AGE 5 Minutes
SESSION_COOKIE_AGE = 5*60

【讨论】:

@shacker 为什么不呢?会话 cookie 会丢失,不是吗? 在 Django 1.10 上完美运行 ;) 谢谢@Slipstream 适用于 2.1 版。谢谢。 我使用的是 Django 3.1.5,直到我设置了 SESSION_EXPIRE_AT_BROWSER_CLOSE = False,它才起作用。 有没有办法让这个触发器成为一个视图,可以将它们重定向到另一个说会话过期的页面?【参考方案7】:

我使用 Django 2.1.7,让 django 会话过期的最简单方法是:

首先你需要使用命令安装 django-session-timeout:

pip install django-session-timeout

那么你需要在 settings.py 中更新你的 SessionTimeoutMiddleware

MIDDLEWARE_CLASSES = [
     ...
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django_session_timeout.middleware.SessionTimeoutMiddleware',
     ...
]

最后需要在settings.py的最后加上SESSION_EXPIRE_SECONDS

SESSION_EXPIRE_SECONDS = 300 # 300 seconds = 5 minutes

默认情况下,会话将在会话开始后 X 秒过期。要在最后一个活动 X 秒后过期会话,请使用以下设置:

SESSION_EXPIRE_AFTER_LAST_ACTIVITY = True

【讨论】:

不幸的是,awsebcli 需要 1.11 版(但不是更高版本)中的包“六”,而 django-session-timeout 强制使用 1.12。所以因此不是我的选择:( 这个解决方案也适用于我的 Django 4.0 项目。谢谢!【参考方案8】:

更新@jhonnylopez 的答案并在一段时间不活动后退出,而不是在给定时间后退出:

settings.py

# Logout after a period of inactivity
INACTIVE_TIME = 15*60  # 15 minutes - or whatever period you think appropriate
SESSION_SERIALIZER = 'django.contrib.sessions.serializers.PickleSerializer'
SESSION_EXPIRE_AT_BROWSER_CLOSE= True
SESSION_COOKIE_AGE = INACTIVE_TIME   # change expired session
SESSION_IDLE_TIMEOUT = INACTIVE_TIME  # logout

middleware.py

from django.contrib.auth import logout
import datetime

from settings import SESSION_IDLE_TIMEOUT


class SessionIdleTimeout(object):
    """Middle ware to ensure user gets logged out after defined period if inactvity."""
    def __init__(self, get_response):
        self.get_response = get_response

    def __call__(self, request):
        if request.user.is_authenticated:
            current_datetime = datetime.datetime.now()
            if 'last_active_time' in request.session:
                idle_period = (current_datetime - request.session['last_active_time']).seconds
                if idle_period > SESSION_IDLE_TIMEOUT:
                    logout(request, 'login.html')
            request.session['last_active_time'] = current_datetime

        response = self.get_response(request)
        return response

【讨论】:

【参考方案9】:

如果您正在寻找简单的 5 分钟后过期并且不关心提示用户或允许他们延长会话,django-session-timeout 效果很好。

pip install django-session-timeout
SESSION_EXPIRE_SECONDS = 300  # 5 min
SESSION_EXPIRE_AFTER_LAST_ACTIVITY = True
SESSION_TIMEOUT_REDIRECT = '/accounts/logout/'  # redirect to whatever page

虽然这是对 5 分钟后会话到期的快速修复,并重定向到指定页面(注销),但它无助于解决本文中解决的一些其他问题,即警告用户或提供延长的机会一个会话。将最后一个活动设置设置为 True,它将继续根据活动延长会话,但是如果他们正在阅读页面或填写需要超过 5 分钟的表格,它会将它们注销,可能会导致您的问题用户取决于您的网站功能。

更多文档在这里:https://pypi.org/project/django-session-timeout/

我还没有实现它,但计划下一步。如果您需要添加提示用户并允许他们选择扩展会话的功能,其他一些帖子推荐了 django-session-security。

这些是不添加自己的中间件的好选择,如果这不是您想要的路线。

【讨论】:

【参考方案10】:

正如 Dmitry Nikitin 所指出的,在调用 login() 之前需要设置会话。您还需要在设置文件中添加SESSION_SAVE_EVERY_REQUEST = True。此设置将随着每个请求不断更新到期时间。因此,在 5 分钟不活动后,会话将过期。

【讨论】:

以上是关于如何在 5 分钟内使 Django 会话过期?的主要内容,如果未能解决你的问题,请参考以下文章

如何由于 Django 中的不活动而使会话过期?

如何在 django 中查找会话是不是已过期

如何在 30 分钟后使 PHP 会话过期?

如何在 django 中设置会话永不过期

PHP 如何在X分钟后过期PHP会话?

如何在 10 分钟不活动后使 PHP 会话过期? [复制]