1. session代理对象
session是一个代理,指向当前请求的SessionMixin实例。只在请求上下文中可用。
| 属性/方法 | 说明 |
|---|---|
session[key] = value |
设置session值 |
session.get(key, default) |
安全获取session值,键不存在时返回default |
session.pop(key, default) |
移除并返回指定键的值 |
session.clear() |
清空所有session数据 |
"key" in session |
检查键是否存在 |
session.permanent |
设为True时,Session在浏览器关闭后仍保持 |
session.modified |
修改嵌套可变对象时需手动设为True |
session.accessed |
session被访问时为True |
session.new |
session是否为新创建 |
2. 基本操作
from flask import Flask, session, redirect, url_for, request app = Flask(__name__) app.secret_key = "your-secret-key" # 设置值 @app.route("/set") def set_session(): session["username"] = "runoob" session["user_id"] = 1001 session["preferences"] = {"theme": "dark", "lang": "zh"} return "Session已设置" # 读取值 @app.route("/get") def get_session(): username = session.get("username", "访客") # 安全获取 # 或直接访问(可能抛出KeyError) # username = session["username"] return f"用户名: {username}" # 检查是否存在 @app.route("/check") def check_session(): if "username" in session: return f"用户已登录: {session['username']}" return "未登录" # 删除特定键 @app.route("/remove") def remove_session(): session.pop("username", None) return "username已移除" # 清空全部 @app.route("/clear") def clear_session(): session.clear() return "Session已清空"
3. 永久Session
默认情况下,Session在浏览器关闭后失效 (会话级别)。通过设置session.permanent = True可使其在浏览器关闭后仍然有效,有效期由PERMANENT_SESSION_LIFETIME配置控制。
from datetime import timedelta # 配置:设置永久session有效期为7天 app.config["PERMANENT_SESSION_LIFETIME"] = timedelta(days=7) @app.route("/login", methods=["POST"]) def login(): session["username"] = request.form.get("username") # 标记为永久session session.permanent = True return redirect(url_for("index"))
4. 重要:modified标记
当修改session中嵌套的可变对象 (如列表、字典)时,Flask无法自动检测到修改 。必须手动设置session.modified = True,否则修改不会保存到Cookie中。
@app.route("/append") def append_item(): # ❌ 错误:直接修改列表,Flask检测不到 if "items" not in session: session["items"] = [] session["items"].append("new_item") # 修改不会保存! # ✅ 正确:手动标记modified if "items" not in session: session["items"] = [] session["items"].append("new_item") session.modified = True # 必须手动标记! return f"Items: {session['items']}" # 替代方案:重新赋值(自动触发modified) @app.route("/set-list") def set_list(): items = session.get("items", []) items.append("new_item") session["items"] = items # 重新赋值,Flask能检测到 return f"Items: {session['items']}"
| 操作类型 | 是否需要手动modified=True |
|---|---|
session["key"] = value(赋值) |
❌ 否(自动检测) |
session.pop("key") |
❌ 否(自动检测) |
session["list"].append(x)(修改嵌套对象) |
✅ 是(必须手动) |
session["dict"]["key"] = value(修改嵌套字典) |
✅ 是(必须手动) |
5. Session相关配置项
| 配置键 | 默认值 | 说明 |
|---|---|---|
SECRET_KEY |
None |
签名Session的密钥,必须设置才能使用Session |
SESSION_COOKIE_NAME |
"session" |
Session Cookie的名称 |
SESSION_COOKIE_DOMAIN |
None |
Cookie的Domain属性 |
SESSION_COOKIE_PATH |
None |
Cookie的Path属性 |
SESSION_COOKIE_HTTPONLY |
True |
禁止JavaScript访问Session Cookie |
SESSION_COOKIE_SECURE |
False |
为True时仅通过HTTPS发送 |
SESSION_COOKIE_SAMESITE |
None |
"Strict"、"Lax"或None |
PERMANENT_SESSION_LIFETIME |
timedelta(days=31) |
永久Session的有效期 |
SESSION_REFRESH_EACH_REQUEST |
True |
每次请求都刷新Session Cookie的有效期 |
生产环境Session配置推荐
# app.py import os from datetime import timedelta app.config.update( SECRET_KEY=os.environ.get("SECRET_KEY"), # 从环境变量读取 SESSION_COOKIE_SECURE=True, # 仅HTTPS传输 SESSION_COOKIE_HTTPONLY=True, # 禁止JavaScript访问 SESSION_COOKIE_SAMESITE="Lax", # 防范CSRF PERMANENT_SESSION_LIFETIME=timedelta(days=7), # 7天有效期 SESSION_REFRESH_EACH_REQUEST=False, # 不自动刷新,减少Cookie写入 )
6. 完整代码示例
from flask import Flask, session, redirect, url_for, request from datetime import timedelta app = Flask(__name__) app.secret_key = "dev-secret-key" app.config["PERMANENT_SESSION_LIFETIME"] = timedelta(days=7) @app.route("/") def index(): username = session.get("username", "访客") items = session.get("items", []) return f""" <h1>欢迎, {username}!</h1> <p>购物车: {items}</p> <p><a href="/login">登录</a> | <a href="/add-item">添加商品</a> | <a href="/logout">退出</a></p> """ @app.route("/login", methods=["GET", "POST"]) def login(): if request.method == "POST": session["username"] = request.form.get("username", "用户") session["items"] = [] session.permanent = True return redirect(url_for("index")) return '<form method="post"><input name="username"><input type="submit"></form>' @app.route("/add-item") def add_item(): if "items" not in session: session["items"] = [] session["items"].append(f"商品{len(session['items']) + 1}") session.modified = True # 修改嵌套列表,必须手动标记! return redirect(url_for("index")) @app.route("/logout") def logout(): session.clear() return redirect(url_for("index"))
7. Session API速查表
| 操作 | 代码 |
|---|---|
| 设置值 | session["key"] = "value" |
| 读取值(安全) | session.get("key", "default") |
| 读取值(直接) | session["key"](键不存在抛KeyError) |
| 检查键是否存在 | "key" in session |
| 删除键 | session.pop("key", None) |
| 清空所有 | session.clear() |
| 设置永久 | session.permanent = True |
| 标记已修改 | session.modified = True |
| 获取所有键 | list(session.keys()) |
8. 安全注意事项
| ⚠️ 风险 | ✅ 防护措施 |
|---|---|
| 密钥泄露导致Session伪造 | SECRET_KEY从环境变量读取,不提交到Git |
| Session被窃取(中间人攻击) | 生产环境启用SESSION_COOKIE_SECURE=True |
| XSS窃取Session | 使用SESSION_COOKIE_HTTPONLY=True |
| CSRF攻击 | 配合SESSION_COOKIE_SAMESITE="Lax"或使用Flask-WTF |
# 生产环境密钥管理最佳实践 import os import secrets # 开发环境:自动生成,但提交到Git时忽略 if os.environ.get("FLASK_ENV") == "development": app.config["SECRET_KEY"] = os.environ.get("SECRET_KEY", secrets.token_hex(32)) else: # 生产环境:必须从环境变量读取 app.config["SECRET_KEY"] = os.environ["SECRET_KEY"]
小结
本章全面讲解了Flask Session的完整API。session代理对象支持字典式操作(session[key]、session.get()、session.pop()、session.clear()、in检查);永久Session通过session.permanent = True启用,有效期由PERMANENT_SESSION_LIFETIME控制;修改嵌套可变对象(如列表append、字典嵌套赋值)时必须手动设置session.modified = True,否则修改不会保存;相关配置项包括SECRET_KEY(必须设置)、SESSION_COOKIE_SECURE、SESSION_COOKIE_HTTPONLY、SESSION_COOKIE_SAMESITE等。Session默认存储在签名Cookie中,数据有4KB大小限制且仅签名未加密,适合存储用户ID等轻量非敏感信息。