Flask入门教程(二十六):Session API——用户会话状态管理

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等轻量非敏感信息。

相关推荐
利威尔xu6 小时前
Go IM 源码实战(14):本地缓存快 3000 倍,失效却难 10 倍
后端·缓存·微服务·面试·golang
逃逸线LOF7 小时前
Ribbon负载均衡原理(Irule组件、源码分析)
后端·spring cloud·ribbon
砚底藏山河7 小时前
python量化自定义周期 K 线合成
java·开发语言·数据库·python·金融
慢云智慧空间7 小时前
从设备智能到空间理解,空间智能终端解决方案商如何重新定义行业标准
后端
视觉小萌新7 小时前
AI Class 3 · Chapter 1:变量、字符串、list/dict、if/for(python学习-小白版-有经验可跳过)
python·学习·list
利威尔xu8 小时前
Go IM 源码实战(13):30 个会话只有 2 个红点,未读数错在三条路径
redis·后端·微服务·面试·golang
薛定谔的猫-菜鸟程序员8 小时前
软件架构设计师开发资料大全(从入门到精通)
后端·python·系统架构·flask·架构设计师
IT_陈寒10 小时前
SpringBoot多环境配置把我坑惨了,这个踩坑经验你最好看看
前端·人工智能·后端
Ramble_Naylor10 小时前
Rust深度解读:Send 与 Sync 的本质与线程安全边界
python·算法·rust
码事漫谈10 小时前
DeepSeek 搞了个 "Super-agent",但不是超级智能
后端