当戈登警局的警官们能够进行身份验证之后,蝙蝠侠希望每位警官的仪表盘能在多次请求之间记住一小部分状态——他们选择的主题、一个 CSRF 令牌、他们最后查看的案件——而无需为此搭建一个数据库。于是他选择了 Robyn 的会话(sessions)。
会话
Robyn 提供签名 Cookie 会话(signed-cookie sessions)。会话是一个存储在客户端、放在防篡改 Cookie 中的小型字典(数据上带有 HMAC-SHA256 签名)。无需服务端存储,且签名意味着客户端无法在不变更签名的情况下篡改其内容。
注意:会话是“签名”的,而非“加密”的。数据只是被编码,因此客户端可以读取——切勿在会话中存放机密信息(密码、原始令牌)。在应用中通过 configure_sessions 一次性启用会话,之后即可在任何处理器中通过 request.session 读写会话——就像身份验证中使用的 request.identity 一样。
from robyn import Robyn
app = Robyn(__file__)
app.configure_sessions(secret_key="keep-me-secret")from robyn import Robyn
app = Robyn(__file__)
app.configure_sessions(secret_key="keep-me-secret")使用 secret_key 调用 configure_sessions。请务必保密该密钥,并在重启以及所有工作进程之间保持稳定——它负责对每一个会话 Cookie 进行签名与校验。
@app.get("/visits")
def visits(request):
request.session["count"] = request.session.get("count", 0) + 1
return f"You have visited {request.session['count']} times"@app.get("/visits")
def visits(request):
request.session["count"] = request.session.get("count", 0) + 1
return f"You have visited {request.session['count']} times"在处理器内部,request.session 是一个类似字典的 Session 对象。像使用 dict 一样读取它、像使用 dict 一样修改它。Robyn 会自动把更新后的会话写回响应 Cookie——但仅当会话确实被修改时才会写入,因此只读请求不会发送 Set-Cookie。
@app.post("/logout")
def logout(request):
request.session.clear()
return "logged out"@app.post("/logout")
def logout(request):
request.session.clear()
return "logged out"要注销用户或丢弃其状态,只需清空会话即可。清空会话会使浏览器中的 Cookie 失效。
配置
configure_sessions 接受以下关键字参数来控制 Cookie:
secret_key(必填)——用于签名 Cookie 的密钥。cookie_name——会话 Cookie 的名称。默认为"session"。max_age——会话有效期(秒),同时作为 Cookie 的Max-Age。默认为 14 天。传入None表示 Cookie 仅在浏览器会话期间有效。path——Cookie 的Path。默认为"/"。domain——Cookie 的Domain。默认为None。secure——仅通过 HTTPS 发送 Cookie。默认为False;生产环境请设为True。http_only——对 JavaScript 隐藏 Cookie。默认为True。same_site——"Strict"、"Lax"或"None"。默认为"Lax"。
工作原理
在底层,configure_sessions 注册了一个全局的 before_request 中间件,将 Cookie 加载并校验为 Session 后挂载到 request.session;以及一个全局的 after_request 中间件,在会话被修改时对其进行签名并写回响应。由于 request.session 在 before_request、处理器与 after_request 三个阶段中是同一个对象,你在处理器中做出的修改,正是最终被写回的内容。
如果你想要显式控制,而不是依赖自动化的中间件,也可以直接使用 SessionManager,通过 manager.load(request) 与 manager.save(session, response) 来手动处理。