尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

Litestar 客户端侧会话(Cookie Session)中间件:CookieBackendConfig 与 ClientSideSessionBackend 完整指南

Litestar 客户端侧会话(Cookie Session)中间件:CookieBackendConfig 与 ClientSideSessionBackend 完整指南 Litestar 客户端侧会话Cookie Session中间件CookieBackendConfig 与 ClientSideSessionBackend 完整指南【免费下载链接】litestarLight, flexible and extensible ASGI framework | Built to scale项目地址: https://gitcode.com/GitHub_Trending/li/litestarLitestar 内置的 Session Middleware 同时支持客户端侧与服务端侧会话。其中客户端侧会话通过litestar.middleware.session.client_side模块实现会话数据经 AES-GCM 加密后直接存入浏览器 Cookie并在 Cookie 超过 4KB 时自动分块存储。本文围绕该模块的CookieBackendConfig配置类与ClientSideSessionBackend后端类完整讲解所有配置参数、加解密与分块原理、过期机制与校验规则并结合仓库源码与单元测试给出可复现的实战方案。读完本文你将能够为 Litestar 应用配置一套加密、无服务端存储依赖的 Cookie 会话并理解其底层安全边界。一、客户端侧会话概述Litestar 的会话中间件由 docs/usage/middleware/builtin-middleware.rstSession Middleware 一节统一介绍它提供两种会话模式客户端侧会话会话数据经加密后存放在浏览器 Cookie 中服务端无需任何存储天然支持多实例水平扩展服务端侧会话仅将随机生成的 Session ID 放入 Cookie实际数据存放在 Litestar 的 stores内存、文件、Redis、Valkey中。客户端侧会话的 API 参考页即本指南对应的 client_side.rst其对外暴露两个核心符号ClientSideSessionBackend负责会话数据的序列化、AES-GCM 加密、Base64 编码、分块与 Cookie 读写CookieBackendConfigBaseBackendConfig的子类集中声明 Cookie 相关配置并校验其合法性。由于两种会话模式都依赖 Cookie一个存放会话数据本体、一个存放会话 ID它们共享大部分 Cookie 配置项公共配置基类定义在 base.py 的BaseBackendConfig中。二、快速上手最小可用配置使用客户端侧会话只需两步创建一个CookieBackendConfig实例并将它的.middleware属性加入应用的中间件列表。仓库中的官方示例见 cookie_backend.pyfrom os import urandom from litestar import Litestar from litestar.middleware.session.client_side import CookieBackendConfig session_config CookieBackendConfig(secreturandom(16)) app Litestar(middleware[session_config.middleware])启动前需要确认cryptography库已安装。ClientSideSessionBackend在模块导入阶段就依赖它见 client_side.pytry: from cryptography.exceptions import InvalidTag from cryptography.hazmat.primitives.ciphers.aead import AESGCM except ImportError as e: raise MissingDependencyException(cryptography) from e因此缺少依赖时会直接抛出MissingDependencyException。可通过 Litestar 的 extra 安装pip install litestar[cryptography]CookieBackendConfig继承自BaseBackendConfigbase.py其.middleware属性本质上是DefineMiddleware(SessionMiddleware, backendself._backend_class(configself))即把配置与后端一起注入SessionMiddleware。而SessionMiddleware的核心流程base.py是请求进入时scope[session] await backend.load_from_connection(connection)从请求 Cookie 中解密加载会话处理期间路由处理器通过request.session读写会话字典响应发出时通过create_send_wrapper包装 ASGIsend在http.response.start消息上调用backend.store_in_message写入会话 Cookie。三、CookieBackendConfig 配置参数全解CookieBackendConfig是BaseBackendConfig[ClientSideSessionBackend]的dataclass子类完整定义于 client_side.py。各参数含义、默认值与约束如下参数类型默认值说明secretbytes必填加密密钥长度必须为 16128 位、24192 位或 32256 位字节keystrsessionCookie 名如sessiondata超过 4KB 分块时命名为session-{分块序号}max_ageintONE_DAY_IN_SECONDS * 1414 天Cookie 最长存活时间秒到期后失效scopesScopes{http, websocket}中间件生效的 ASGI 作用域默认同时覆盖 HTTP 与 WebSocketpathstr/Cookie 生效的 URL 路径片段domainstr \| NoneNoneCookie 生效的域名secureboolFalse为True时仅允许通过 HTTPS 传输 CookiehttponlyboolTrue为True时禁止 JavaScript 通过document.cookie读取samesitelax \| strict \| nonelax控制跨站请求是否携带 Cookieexcludestr \| list[str] \| NoneNone一个或多个路径模式匹配的请求跳过会话中间件exclude_opt_keystrskip_session在具体路由上通过该键禁用会话中间件的标识符其中key、max_age、scopes、path、domain、secure、httponly、samesite、exclude、exclude_opt_key均继承自公共基类BaseBackendConfigbase.py因此客户端侧与服务端侧可配置项一致。3.1 secretAES-GCM 加密密钥secret是客户端侧会话的安全根基。它用于初始化AESGCM(config.secret)见 client_side.py会话数据用它加密后写入 Cookie。密钥长度直接决定加密强度16 字节 → AES-12824 字节 → AES-19232 字节 → AES-256。非法长度会在__post_init__阶段抛出ImproperlyConfiguredExceptionclient_side.pydef __post_init__(self) - None: if len(self.key) 1 or len(self.key) 256: raise ImproperlyConfiguredException(key must be a string with a length between 1-256) if self.max_age 1: raise ImproperlyConfiguredException(max_age must be greater than 0) if len(self.secret) not in {16, 24, 32}: raise ImproperlyConfiguredException(secret length must be 16 (128 bit), 24 (192 bit) or 32 (256 bit))官方示例使用urandom(16)生成 128 位密钥这也是最低配置。注意secret必须保密且需在服务重启后保持一致否则客户端已有的会话 Cookie 将无法解密。3.2 keyCookie 名称与分块命名规则key决定 Cookie 的名字默认session。当会话数据加密编码后超过单条 Cookie 容量约 4KB时会被拆成多条 Cookie命名变为key-0、key-1……client_side.pyif len(data) 1: return [Cookie(valuedata[0].decode(utf-8), keyself.config.key, **cookie_params)] return [ Cookie(valuedatum.decode(utf-8), keyf{self.config.key}-{i}, **cookie_params) for i, datum in enumerate(data) ]后端通过编译好的正则re.compile(rf{self.config.key}(?:-\d)?)client_side.py识别属于本会话的全部 Cookie 键get_cookie_keys/get_cookie_key_set会从请求 Cookie 中筛选出匹配项。3.3 max_age过期时间max_age控制会话有效时长默认 14 天ONE_DAY_IN_SECONDS * 14其中ONE_DAY_IN_SECONDS 60 * 60 * 24定义于 base.py。它有两重作用作为会话数据加密时的“关联数据”Associated Data写入载荷加载时校验expires_at 当前时间过期直接返回空会话见下文解密流程写入 Cookie 时作为max_age属性浏览器侧也会在到期后丢弃该 Cookie。3.4 路径排除与路由级开关exclude接受字符串或字符串列表内容为路径模式SessionMiddleware将其透传给AbstractMiddleware匹配的请求不加载也不写入会话base.pyexclude_opt_key默认值skip_session。在路由处理器上把该键的值设为True即可针对单个路由关闭会话中间件而不影响全局配置。四、ClientSideSessionBackend 原理剖析ClientSideSessionBackend继承自BaseSessionBackend[CookieBackendConfig]实现数据落盘Cookie与加载的完整链路。其关键设计可从 client_side.py 与单元测试 test_client_side_backend.py 相互印证。4.1 写入链路 dump_datadump_dataclient_side.py完成“序列化 → 加密 → 编码 → 分块”四个步骤serialized self.serialize_data(data, scope) associated_data encode_json({expires_at: round(time.time()) self.config.max_age}) nonce urandom(NONCE_SIZE) encrypted self.aesgcm.encrypt(nonce, serialized, associated_dataassociated_data) encoded b64encode(nonce encrypted AAD associated_data) return [encoded[i : i CHUNK_SIZE] for i in range(0, len(encoded), CHUNK_SIZE)]要点序列化调用BaseSessionBackend.serialize_database.py优先使用 scope 中注册的序列化器否则回退到default_serializer支持 pydantic 模型与 numpy 类型关联数据AAD将{expires_at: 当前时间 max_age}作为 AES-GCM 的附加认证数据保证过期时间被篡改时解密直接失败Nonce通过os.urandom生成 12 字节随机数与密文一同编码编码与分块nonce 密文 AAD 关联数据整体做 Base64 编码再按CHUNK_SIZE 4096 - 64切块确保每一块都小于 4KB 的 Cookie 容量上限。4.2 读取链路 load_dataload_dataclient_side.py是写入的逆过程decoded b64decode(b.join(data)) nonce decoded[:NONCE_SIZE] aad_starts_from decoded.find(AAD) associated_data decoded[aad_starts_from:].replace(AAD, b) if aad_starts_from ! -1 else None if associated_data and decode_json(valueassociated_data)[expires_at] round(time.time()): encrypted_session decoded[NONCE_SIZE:aad_starts_from] decrypted self.aesgcm.decrypt(nonce, encrypted_session, associated_dataassociated_data) return self.deserialize_data(decrypted) return {}先把各分块拼接后 Base64 解码提取前 12 字节为 nonce按AAD badditional_authenticated_data定位并还原关联数据校验expires_at是否大于当前时间过期直接返回空字典{}校验通过则用 AES-GCM 解密并反序列化回会话字典。单元测试 test_client_side_backend.py 专门验证了过期场景将time.timemock 推进到max_age 1秒之后load_data返回{}。4.3 异常与安全性处理load_from_connectionclient_side.py对解密失败做了容错if cookie_keys : self.get_cookie_keys(connection): data [connection.cookies[key].encode(utf-8) for key in cookie_keys] with contextlib.suppress(InvalidTag, binascii.Error): return self.load_data(data) return {}InvalidTag密钥不匹配、密文被篡改或关联数据被修改时AES-GCM 认证失败视为空会话而不是抛错中断请求binascii.ErrorCookie 内容不是合法 Base64 时同样静默降级为空会话。测试 test_dump_and_load_data 则验证了往返一致性dump_data的每个分块不超过CHUNK_SIZE且load_data(dump_data(session)) session。4.4 会话 Cookie 的写入与清理store_in_messageclient_side.py在响应阶段执行若当前会话非空dump_data后创建 Cookie 列表写入Set-Cookie头并记录已写键若会话为空或已置为Empty清空全部会话 Cookie会话缩小导致分块减少时cookies_to_clear connection_cookies - response_cookies只清除多余的旧分块清理时通过Cookie(valuenull, keycookie_key, expires0, ...)使浏览器立即删除对应 Cookie。4.5 get_session_id客户端侧会话无 IDget_session_id直接返回Noneclient_side.py。这是客户端侧与服务端侧的关键差异服务端侧需要 Session ID 去存储中检索数据而客户端侧数据本身就在 Cookie 里不存在独立的会话标识。五、配置校验规则与测试印证CookieBackendConfig.__post_init__中实现的校验规则均有对应测试覆盖见 test_client_side_backend.py配置项合法取值非法取值抛出ImproperlyConfiguredExceptionsecret16、24、32 字节17、4、100 字节及空值test_secret_validationkey长度 1–256 的字符串空字符串、257 字符test_key_validationmax_age≥ 1 的整数0、负数test_max_age_validation在真实请求中SessionMiddleware与CookieBackendConfig的集成可通过create_test_client验证测试中大量使用RequestFactory与create_test_client模拟会话读写与 Cookie 分块场景这也提示了在你自己的项目中可以使用 litestar.testing 以同样的方式为会话功能编写端到端测试。六、服务端侧会话对比与选型建议Litestar 同时提供服务端侧会话配置类为ServerSideSessionConfig见 server_side.rst二者对比如下维度客户端侧Cookie服务端侧Store数据存放加密后存放于浏览器 Cookie服务端存储内存/文件/Redis/Valkey服务端存储依赖无需要配置 stores会话标识无get_session_id返回NoneCookie 中存放随机 Session ID加密要求必须提供 16/24/32 字节secret不涉及数据加密水平扩展天然无状态任意实例可服务需共享存储如 RedisCookie 体积随会话数据增长超 4KB 自动分块恒定极小仅 ID选型建议若会话数据量小、追求无状态部署与多实例弹性伸缩优先选择客户端侧会话若会话数据量大、需要服务端主动失效如注销踢人、或对 Cookie 体积敏感则选择服务端侧会话并搭配 Redis/Valkey 存储。七、小结客户端侧会话通过CookieBackendConfig(secreturandom(16))一行配置即可接入 Litestar 中间件栈前提是安装litestar[cryptography]extra数据链路为“序列化 → AES-GCM 加密含过期时间 AAD→ Base64 编码 → 按CHUNK_SIZE分块”读取时按逆序校验认证与过期时间任何异常均安全降级为空会话所有 Cookie 属性key、max_age、secure、httponly、samesite、path、domain等集中在CookieBackendConfig声明并受__post_init__严格校验通过exclude与exclude_opt_key可以灵活控制路径级与路由级的会话开关。相关参考文件API 参考页 client_side.rst、公共基类 base.py、后端实现 client_side.py、使用指南 builtin-middleware.rstSession Middleware 一节、官方示例 cookie_backend.py 与 cookies_full_example.py、单元测试 test_client_side_backend.py。【免费下载链接】litestarLight, flexible and extensible ASGI framework | Built to scale项目地址: https://gitcode.com/GitHub_Trending/li/litestar创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表