浏览器 Cookie 永不过期

ame*_*ian 2 cookies python-3.x cookie-httponly fastapi uvicorn

我第一次使用 HTTpOnly Cookie 实现登录身份验证就我而言,当用户使用 fastapi 和 uvicorn 在Python 服务中调用登录方法时创建 cookie 。

我已经阅读了MDN文档来实现 expires 属性,因此,浏览器会在时间到期时删除此 cookie。

我已经使用 http.cookies 和Morsel在 Python 中实现了 Cookie,以应用HttpOnly属性,如下所示:

from http import cookies
from fastapi import FastAPI, Response, Cookie, Request
from fastapi.responses import HTMLResponse, FileResponse
from fastapi.staticfiles import StaticFiles
from fastapi.templating import Jinja2Templates

mytoken = 'blablabla'

def getUtcDate():
    sessionDate = datetime.now()
    sessionDate += timedelta(minutes=2)
    return sessionDate.strftime('%a, %d %b %Y %H:%M:%S GMT')

@app.get('cookietest')
def getCookie(response: Response):
   cookie = cookies.Morsel()
   cookie['httponly'] = True
   cookie['version'] = '1.0.0'
   cookie['domain'] = '127.0.0.1'
   cookie['path'] = '/'
   cookie['expires'] = getUtcDate()
   cookie['max-age'] = 120
   cookie['samesite'] = 'Strict'
   cookie.set("jwt", "jwt", mytoken)

   response.headers.append("Set-Cookie", cookie.output())

   return {'status':'ok'}
Run Code Online (Sandbox Code Playgroud)

这样做,当我调用“cookietest”端点时,Cookie 在浏览器中看起来正确,证据如下:

带有有效期的 Cookie

如图所示,cookie 在 Expires / Max-Age 中有一个过期日期时间:“Wed, 12 Oct 2022 11:24:58 GMT”,登录后 2 分钟(如果用户在 14:05 登录: 00,cookie 于 14:07:00 过期)

我的问题是,当超过过期时间时,任何浏览器都不会删除 cookie,所以这让我感到困惑。如果我过了几分钟然后向另一个端点(例如http://127.0.0.1:8000/info)发出请求,则 cookie 仍然存在于 http 标头中。

问题是什么?我做错了什么?我正在阅读大量有关 cookie 存储和过期的文档,但我看不到任何有关此问题的信息。

非常感谢 问候

编辑:问题已解决

正如Chris所说,使用 FastApi 中的 set_cookie 方法解决了问题。

我仍然想知道为什么MSD文档指示日期格式必须是特定的格式,这不会导致浏览器删除Cookie,但指示以秒为单位的时间可以正常工作。

@app.get("/cookietest")
async def cookietest(response: Response):
    response.set_cookie(
        key='jwt', 
        value=getToken(), 
        max_age=120, 
        expires=120, 
        path='/', 
        secure=False, 
        httponly=True, 
        samesite="strict", 
        domain='127.0.0.1'
    )
    return {"Result": "Ok"}
Run Code Online (Sandbox Code Playgroud)

Chr*_*ris 5

使用该expires标志时,日期必须完全符合您当前使用的格式以及GMT(格林威治标准时间)时区。您的 cookie 在创建后 2 分钟内不会过期的原因是您使用的是datetime.now(),它返回当前的本地日期和时间。

\n

因此,举例来说,如果您当前的本地时区是GMT+2,时间是20:30:00(因此,GMT时间是18:30:00),创建一个过期的 cookie20:32:00 GMT实际上会告诉浏览器在 2 小时 2 分钟后删除该 cookie(从创建它的时间算起) )。Expires / Max-Age如果您查看浏览器的 DevTools 中的cookie列(例如,在 Chrome 上,转到NetworkDevTools 中的选项卡,单击请求的名称,然后单击选项卡),您会Cookies注意到Z日期时间的末尾,这意味着UTC(协调世界时)\xe2\x80\x94,即与 UTC 的零小时-分钟-秒的偏移量。您还可以检查响应标头,您可以在其中看到 cookie 的expires标志设置为20:32:00 GMT之间没有明显的时间差异UTCGMT(如果您想了解更多关于它们的差异,请查看这篇文章)。

\n

因此,您可以在代码中替换.now()为:.utcnow()

\n
from datetime import timedelta, datetime\n\ndef get_expiry():\n    expiry = datetime.utcnow()\n    expiry += timedelta(seconds=120)\n    return expiry.strftime(\'%a, %d-%b-%Y %T GMT\')\n
Run Code Online (Sandbox Code Playgroud)\n

或使用time.gmtime(),传递secstime.time ()(返回以秒为单位的时间)加上所需的租约时间(以秒为单位)作为参数:

\n
import time\n\ndef get_expiry():\n    lease = 120  # seconds\n    end = time.gmtime(time.time() + lease)\n    return time.strftime(\'%a, %d-%b-%Y %T GMT\', end)\n
Run Code Online (Sandbox Code Playgroud)\n

对于上述两种方法,请使用:

\n
cookie[\'expires\'] = get_expiry()\n
Run Code Online (Sandbox Code Playgroud)\n

您还可以使用未记录的方式直接以秒为单位传递到期时间。例如:

\n
cookie[\'expires\'] = 120\n
Run Code Online (Sandbox Code Playgroud)\n

另一种方法expiresmax-ageflag ,它指定 cookie 从当前时刻起的过期时间(以秒为单位)(与上面的方式类似)。如果设置为零或负值,则 cookie 将被立即删除。例子:

\n
cookie[\'max-age\'] = 120\n
Run Code Online (Sandbox Code Playgroud)\n

笔记:

\n

如果 和expires均已max-age设置,max-age则具有优先权(请参阅 MDN 上的相关文档)。

\n

另外,根据RFC 6265

\n
\n

4.1.2.1. 属性Expires

\n

Expires属性指示 cookie 的最长生命周期,\n表示为cookie 过期的日期和时间。在指定日期过去之前,\n用户代理不需要保留 cookie。事实上,用户代理经常由于内存压力或隐私问题而逐出 cookie。

\n

4.1.2.2. 属性Max-Age

\n

Max-Age属性指示 cookie 的最长生命周期,\n表示为cookie 过期之前的秒数。用户代理不需要在指定的时间内保留 cookie。事实上,用户代理经常由于内存压力或隐私问题而逐出 cookie。

\n
NOTE: Some existing user agents do not support the Max-Age \nattribute. User agents that do not support the Max-Age attribute \nignore the attribute.\n
Run Code Online (Sandbox Code Playgroud)\n

如果 cookie同时Max-Age具有和属性Expires,则属性Max-Age具有优先权并控制 cookie 的过期日期。如果 cookie既没有Max-Age也没有\ Expiresn 属性,则用户代理将保留该 cookie 直到“当前会话结束”(由用户代理定义)。

\n
\n

另请注意,正如MDN 文档中有关该expires标志的内容所述:

\n
\n

警告:许多 Web 浏览器具有会话恢复功能,该功能将保存所有选项卡并在下次使用浏览器时恢复它们。\n会话 cookie 也将被恢复,就好像浏览器从未关闭过\n一样。

\n
\n

另一件需要注意的事情是,自 2022 年 9 月起,Chrome 将 cookie 的有效期限制max-age为 400 天

\n
\n

当使用显式属性设置 cookie 时,Expires/Max-Age\n值现在将限制为未来不超过 400 天。\n以前没有限制,并且 cookie 可能会在未来几千年\n过期。

\n
\n

使用 FastAPI/Starlette

\n

还应该注意的是,FastAPI/Starlette 提供了一种更简单的方法来在Response对象上设置 cookie,使用set_cookie方法,如本答案中所述。根据Starlette 文档

\n
\n
    \n
  • max_age- 一个整数,定义 cookie 的生存期(以 为单位) 。负整数或 的值0将立即丢弃 cookie。Optional
  • \n
  • expires-定义 cookie 过期之前的秒数的整数。Optional
  • \n
\n
\n

FastAPI 文档中的示例

\n
cookie[\'expires\'] = get_expiry()\n
Run Code Online (Sandbox Code Playgroud)\n