【问题标题】:Django sessions expiring despite calling set_expiry(0)尽管调用 set_expiry(0),Django 会话仍将过期
【发布时间】:2019-08-25 16:41:46
【问题描述】:

我正在尝试在 django 的内置 LoginView 中实现一个“记住我”复选框,正如 this question 上所建议的那样,但即使我调用 set_expiry(0),会话仍然在 SESSION_COOKIE_AGE 之后过期,不管 cookie过期日期(正确设置为 1969)。

我正在使用 django 2.1.7 和 python 3.7.2,我的settings.py 上唯一与会话相关的设置是SESSION_COOKIE_AGE,它设置为 5 秒以用于休息。

Django 似乎默认使用数据库后端。我正在使用 sqlite 进行开发。

这是我的视图类:

class UserLoginView(LoginView):
    form_class = registration.UserLoginForm

    def form_valid(self, form):
        remember = form.data.get('remember_me', False)
        if remember:
            self.request.session.set_expiry(0)
        return super(UserLoginView, self).form_valid(form)

这是原始 LoginView form_valid 方法(上面被覆盖)

class LoginView(SuccessURLAllowedHostsMixin, FormView):

...

    def form_valid(self, form):
        """Security check complete. Log the user in."""
        auth_login(self.request, form.get_user())
        return HttpResponseRedirect(self.get_success_url())

...

如您所见,我使用的是自定义 form_class。一个非常简单的默认表单覆盖:

class UserLoginForm(AuthenticationForm):
    remember_me = BooleanField(required=False)

如果我在 set_expiry 调用后立即使用调试器,我可以看到会话过期时间仍然是默认的 5 秒:

> /project/app/views/accounts.py(64)form_valid()
-> return super(UserLoginView, self).form_valid(form)
(Pdb) self.request.session.get_expiry_age()
5

如果我让请求完成并重定向,到达下一个视图并最终呈现我拥有的模板,我会得到类似的结果:

...

{{ request.session.get_expiry_age }}

...

渲染结果也是5(当前默认)。

果然,5秒后,如果你刷新页面,django会带你回到登录界面。

我在这里做错了什么?如果有人能澄清“Web 浏览器已关闭”是什么意思,那就太好了? https://docs.djangoproject.com/en/2.2/topics/http/sessions/#django.contrib.sessions.backends.base.SessionBase.set_expiry

【问题讨论】:

    标签: python django session


    【解决方案1】:

    TL; DR; 似乎 Django 不支持无限或真正未定义的到期会话时间。如果您需要延长有效期,请将其设置为 30 天或更长时间。

    来自Django documentation

    如果值为 0,则用户的会话 cookie 将在用户的 Web 浏览器关闭时过期。

    虽然这里不清楚,但似乎将到期时间设置为0 在将其设置为None 时具有类似的行为:它将回退到默认会话到期策略。这里的区别在于,当将其设置为0 时,我们还推断出session should be expired right after the user closes the browser。在这两种情况下,SESSION_COOKIE_AGE 的作用类似于会话 max-age 值。

    我相信您可以设置一个更大的数字来解决这个问题,例如,相当于 100 年或更长时间。我个人的建议是在用户检查“记住我”字段时指定 30 天的到期时间。当你指定一个大于零的正整数时,Django 不会回退到SESSION_COOKIE_AGE 设置。

    如果您想知道为什么即使在指定 0 秒的过期时间后仍然得到 5 秒,这里是从 get_expiry_age 函数中提取的源代码:

    if not expiry:   # Checks both None and 0 cases
        return settings.SESSION_COOKIE_AGE
    if not isinstance(expiry, datetime):
        return expiry
    

    最后的考虑:

    • Django 文档还有一些改进空间
    • 似乎刷新标签也可能使会话无效

    【讨论】:

    • 好的,我可以理解为什么get_expiry_age 返回默认值,但是如果它设置为 0 并且我设置为 0 并且我没有关闭浏览器窗口。
    猜你喜欢
    • 2013-01-06
    • 1970-01-01
    • 2013-08-22
    • 2020-03-17
    • 2014-12-22
    • 1970-01-01
    • 2020-04-20
    • 2013-02-21
    • 1970-01-01
    相关资源
    最近更新 更多