- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我第一次实现使用 HTTPOnly Cookie 的登录身份验证。就我而言,当用户使用 fastapi 和 uvicorn 在 Python 服务 中调用登录方法时,它会创建 cookie。
我已阅读MDN文档来实现expires属性,因此,浏览器会在时间到期时删除此cookie。
我已经在 Python 中使用 http.cookies 和 Morsel 实现了 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'}
这样做,当我调用“cookietest”端点时,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 header 中。
有什么问题吗?我做错了什么?我正在阅读大量有关 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"}
最佳答案
使用expires
标志时,日期必须完全采用您当前使用的格式,并且采用GMT
(格林威治标准时间)时区。您的 cookie 在创建 2 分钟后不会过期的原因是您正在使用 datetime.now() ,返回当前本地日期和时间。
因此,例如,如果您当前的本地时区是 GMT+2
,时间是 20:30:00
(因此,GMT
时间是18:30:00
),创建一个在20:32:00 GMT
过期的cookie实际上会告诉浏览器在2小时2分钟后删除这个cookie (从创建之时起)。如果您在浏览器的 DevTools 中查看 cookie 的 Expires/Max-Age
列(例如,在 Chrome 上,转到 DevTools 中的 Network
选项卡,单击请求的名称并然后在 Cookies
选项卡上),您会注意到日期时间末尾有一个 Z
,这意味着 UTC
(协调世界时)即,与 UTC 的偏移量为零时-分-秒。您还可以检查响应 header ,在其中您可以看到 Cookie 的 expires
标志设置为 20:32:00 GMT
。没有明显的time difference between UTC
and GMT
(如果您想了解更多关于它们的差异,请查看此 post)。
因此,您可以将 .now()
替换为 .utcnow()
在您的代码中:
from datetime import timedelta, datetime
def get_expiry():
expiry = datetime.utcnow()
expiry += timedelta(seconds=120)
return expiry.strftime('%a, %d-%b-%Y %T GMT')
或使用time.gmtime() ,将 time.time() 作为 secs
参数传递(返回以秒为单位的时间)加上所需的租用时间(以秒为单位):
import time
def get_expiry():
lease = 120 # seconds
end = time.gmtime(time.time() + lease)
return time.strftime('%a, %d-%b-%Y %T GMT', end)
对于上述两种方法,请使用:
cookie['expires'] = get_expiry()
您还可以使用未记录的方式直接以秒为单位传递到期时间。例如:
cookie['expires'] = 120
expires
的替代方法是 max-age
标志,它指定 cookie 从当前时刻开始的过期时间(以秒为单位)(与上面的方式类似)。如果设置为零或负值,则 cookie 将被立即删除。示例:
cookie['max-age'] = 120
如果同时设置了 expires
和 max-age
,则 max-age
优先(请参阅相关 documentation on MDN )。
此外,根据RFC 6265 :
4.1.2.1. The
Expires
AttributeThe
Expires
attribute indicates the maximum lifetime of the cookie,represented as the date and time at which the cookie expires. The useragent is not required to retain the cookie until the specified datehas passed. In fact, user agents often evict cookies due to memorypressure or privacy concerns.4.1.2.2. The
Max-Age
AttributeThe
Max-Age
attribute indicates the maximum lifetime of the cookie,represented as the number of seconds until the cookie expires. Theuser agent is not required to retain the cookie for the specifiedduration. In fact, user agents often evict cookies due to memorypressure or privacy concerns.NOTE: Some existing user agents do not support the Max-Age
attribute. User agents that do not support the Max-Age attribute
ignore the attribute.If a cookie has both the
Max-Age
and theExpires
attribute, theMax-Age
attribute has precedence and controls the expiration date ofthe cookie. If a cookie has neither theMax-Age
nor theExpires
attribute, the user agent will retain the cookie until "the currentsession is over" (as defined by the user agent).
另请注意,如 MDN documentation 中所述关于expires
标志:
Warning: Many web browsers have a session restore feature that will save all tabs and restore them the next time the browser is used.Session cookies will also be restored, as if the browser was neverclosed.
另一件事需要注意的是,自 2022 年 9 月以来,Chrome limits the cookie's max-age
to 400 days :
When cookies are set with an explicit
Expires/Max-Age
attribute thevalue will now be capped to no more than 400 days in the future.Previously, there was no limit and cookies could expire as much asmultiple millennia in the future.
还应该注意的是,FastAPI/Starlette 提供了一种更简单的方法来在 Response
对象上设置 cookie,使用 set_cookie
方法,如 this answer 中所述。根据Starlette documentation :
max_age
- An integer that defines the lifetime of the cookie in seconds. A negative integer or a value of0
will discardthe cookie immediately.Optional
expires
- An integer that defines the number of seconds until the cookie expires.Optional
示例来自FastAPI documentation :
from fastapi import FastAPI, Response
app = FastAPI()
@app.post('/')
def create_cookie(response: Response):
response.set_cookie(key='token', value='token-value', max_age=120, expires=120, httponly=True)
return {'message': 'success'}
关于python-3.x - 浏览器 Cookie 永不过期,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/74041393/
问题故障解决记录 -- Java RMI Connection refused to host: x.x.x.x .... 在学习JavaRMI时,我遇到了以下情况 问题原因:可
我正在玩 Rank-N-type 并尝试输入 x x .但我发现这两个函数可以以相同的方式输入,这很不直观。 f :: (forall a b. a -> b) -> c f x = x x g ::
这个问题已经有答案了: How do you compare two version Strings in Java? (31 个回答) 已关闭 8 年前。 有谁知道如何在Java中比较两个版本字符串
这个问题已经有答案了: How do the post increment (i++) and pre increment (++i) operators work in Java? (14 个回答)
下面是带有 -n 和 -r 选项的 netstat 命令的输出,其中目标字段显示压缩地址 (127.1/16)。我想知道 netstat 命令是否有任何方法或选项可以显示整个目标 IP (127.1.
我知道要证明 : (¬ ∀ x, p x) → (∃ x, ¬ p x) 证明是: theorem : (¬ ∀ x, p x) → (∃ x, ¬ p x) := begin intro n
x * x 如何通过将其存储在“auto 变量”中来更改?我认为它应该仍然是相同的,并且我的测试表明类型、大小和值显然都是相同的。 但即使 x * x == (xx = x * x) 也是错误的。什么
假设,我们这样表达: someIQueryable.Where(x => x.SomeBoolProperty) someIQueryable.Where(x => !x.SomeBoolProper
我有一个字符串 1234X5678 我使用这个正则表达式来匹配模式 .X|..X|X. 我得到了 34X 问题是为什么我没有得到 4X 或 X5? 为什么正则表达式选择执行第二种模式? 最佳答案 这里
我的一个 friend 在面试时遇到了这个问题 找到使该函数返回真值的 x 值 function f(x) { return (x++ !== x) && (x++ === x); } 面试官
这个问题在这里已经有了答案: 10年前关闭。 Possible Duplicate: Isn't it easier to work with foo when it is represented b
我是 android 的新手,我一直在练习开发一个针对 2.2 版本的应用程序,我需要帮助了解如何将我的应用程序扩展到其他版本,即 1.x、2.3.x、3 .x 和 4.x.x,以及一些针对屏幕分辨率
为什么案例 1 给我们 :error: TypeError: x is undefined on line... //case 1 var x; x.push(x); console.log(x);
代码优先: # CASE 01 def test1(x): x += x print x l = [100] test1(l) print l CASE01 输出: [100, 100
我正在努力温习我的大计算。如果我有将所有项目移至 'i' 2 个空格右侧的函数,我有一个如下所示的公式: (n -1) + (n - 2) + (n - 3) ... (n - n) 第一次迭代我必须
给定 IP 字符串(如 x.x.x.x/x),我如何或将如何计算 IP 的范围最常见的情况可能是 198.162.1.1/24但可以是任何东西,因为法律允许的任何东西。 我要带198.162.1.1/
在我作为初学者努力编写干净的 Javascript 代码时,我最近阅读了 this article当我偶然发现这一段时,关于 JavaScript 中的命名空间: The code at the ve
我正在编写一个脚本,我希望避免污染 DOM 的其余部分,它将是一个用于收集一些基本访问者分析数据的第 3 方脚本。 我通常使用以下内容创建一个伪“命名空间”: var x = x || {}; 我正在
我尝试运行我的test_container_services.py套件,但遇到了以下问题: docker.errors.APIError:500服务器错误:内部服务器错误(“ b'{” message
是否存在这两个 if 语句会产生不同结果的情况? if(x as X != null) { // Do something } if(x is X) { // Do something } 编
我是一名优秀的程序员,十分优秀!