【问题标题】:Django File-based session doesn't expireDjango 基于文件的会话不会过期
【发布时间】:2012-04-29 04:26:36
【问题描述】:

我刚刚意识到,当我使用基于文件的会话引擎时,我的会话不会过期。查看基于文件的会话的 Django 代码,Django 不会为会话存储任何过期信息,因此除非手动删除会话文件,否则它永远不会过期。

这对我来说似乎是一个错误,因为数据库支持的会话工作正常,而且我相信无论后端开发人员选择什么会话,它们的行为都应该相似。

切换到数据库支持的会话对我来说不是一个选项,因为我需要将用户的会话存储在文件中。

任何人都可以发光吗? 这真的是一个错误吗? 如果是,您建议我如何解决?

谢谢!

【问题讨论】:

    标签: django session


    【解决方案1】:

    看来你是对的。至少在 django 1.4 中,使用django.contrib.sessions.backends.file 完全忽略了SESSION_COOKIE_AGE。我不确定这是否真的是一个错误,或者只是没有记录。

    如果你真的需要这个功能,你可以基于 contrib 中的文件后端创建你自己的会话引擎,但是用过期功能扩展它。

    打开django/contrib/sessions/backends/file.py 并添加以下导入:

    import datetime
    from django.utils import timezone
    

    然后,在load 方法中添加两行,使其如下所示:

    def load(self):
        session_data = {}
        try:
            session_file = open(self._key_to_file(), "rb")
            if (timezone.now() - datetime.datetime.fromtimestamp(os.path.getmtime(self._key_to_file()))).total_seconds() > settings.SESSION_COOKIE_AGE:
                raise IOError
            try:
                file_data = session_file.read()
                # Don't fail if there is no data in the session file.
                ....
    

    这实际上将比较会话文件上的最后修改日期以使其过期。

    将此文件保存在您的项目中的某处并将其用作您的SESSION_ENGINE 而不是'django.contrib.sessions.backends.file'

    如果您希望会话因不活动而超时,您还需要在设置中启用SESSION_SAVE_EVERY_REQUEST

    【讨论】:

    • 是的,我也在考虑这条路线作为最后的选择。
    • 如果这确实是一个错误,我可能应该在 Django 用户或 Django 开发人员邮件列表中询问
    • 为什么需要启用SESSION_SAVE_EVERY_REQUEST?通过在每次发出请求时设置新的修改时间,这是否会破坏会话过期的目的?
    • 如果没有SESSION_SAVE_EVERY_REQUEST,会话将在SESSION_COOKIE_AGE 秒后过期,无论活动如何。如果这就是你想要的,那么不要打扰SESSION_SAVE_EVERY_REQUEST。如果您希望它仅在 SESSION_COOKIE_AGE 不活动秒后过期,那么您希望 SESSION_SAVE_EVERY_REQUESTTrue
    • 哦,好的,知道了。无论活动如何,我都想使会话到期。感谢您及时的回复。顺便说一句,您能否更新您的答案以提及这一点(SESSION_SAVE_EVERY_REQUEST 的实际目的)?它可能对其他人有帮助。
    【解决方案2】:

    一个选项是在您存储会话的目录中使用tmpwatch

    【讨论】:

    • 我喜欢这个想法,因为它很容易实现。但是,它要求系统有tmpwatch
    【解决方案3】:

    我在Django 3.1 上遇到了类似的问题。在我的例子中,我的程序在检查会话到期之前使用整数参数(int 数据类型)调用函数 set_expiry(value)

    根据Django documentation,参数valueset_expiry()的数据类型可以是intdatetimetimedelta。但是对于基于文件的会话,只有在将int 参数预先传递给set_expiry() 时,expiry check inside load() 才能正常工作,并且datetimeset_expiry()timedelta 参数不会发生此类问题。

    简单的解决方案(解决方法?)是避免int 参数为set_expiry(value),您可以通过子类化django.contrib.sessions.backends.file.SessionStore 并覆盖set_expiry(value)(下面的代码示例)来实现,并相应地更改参数SESSION_ENGINE settings.py

    from datetime import timedelta
    from django.contrib.sessions.backends.file import SessionStore as FileSessionStore
    
    class SessionStore(FileSessionStore):
        def set_expiry(self, value):
            """ force to convert to timedelta format """
            if value and isinstance(value, int):
                value = timedelta(seconds=value)
            super().set_expiry(value=value)
    
    

    注意: 也可以将 timedeltadatetime 传递给 set_expiry(value) ,但您需要 handle serialization issue on datetime object

    【讨论】:

      猜你喜欢
      • 2023-04-06
      • 1970-01-01
      • 2012-08-02
      • 2016-06-22
      • 1970-01-01
      • 1970-01-01
      • 2015-01-31
      • 2013-02-22
      • 2011-09-18
      相关资源
      最近更新 更多