Flask 教程

Flask Session 与 Cookie

在 Web 开发中,HTTP 协议是无状态的,这意味着服务器无法自动记住“你是谁”。为了解决这个问题,我们引入了 CookieSession 来维持客户端和服务器之间的状态。

在 Flask 中,这两者的使用非常优雅,但 Flask 的 Session 机制与传统的 Java/PHP 有所不同,需要特别注意。


💡 核心概念区分

特性CookieSession (Flask 默认实现)
存储位置客户端(浏览器)客户端(以加密签名的 Cookie 形式)
安全性较低,用户可查看和篡改较高,用户可查看但无法篡改(有签名)
容量限制约 4KB约 4KB(受限于 Cookie 大小)
适用场景记住用户名、偏好设置、追踪 ID用户登录状态、购物车临时数据

⚠️ 重要提示:Flask 默认的 Session 是客户端 Session。它把数据序列化后,用 SECRET_KEY 签名,然后作为 Cookie 发给浏览器。服务器端不保存任何 Session 数据。


1. 操作 Cookie

Cookie 是附加在 HTTP 请求和响应头中的。因此,读取 Cookie 用 request,设置/删除 Cookie 用 response

代码示例:

纯文本
plaintext
from flask import Flask, request, make_response

app = Flask(__name__)

# 1. 设置 Cookie
@app.route('/set-cookie')
def set_cookie():
    # 必须使用 make_response 将返回值包装成响应对象
    resp = make_response('Cookie 设置成功!')

    # 设置 Cookie: key, value, max_age(有效期,单位:秒)
    # 如果不设置 max_age,则默认为会话级 Cookie(浏览器关闭即失效)
    resp.set_cookie('username', 'john_doe', max_age=3600) 
    resp.set_cookie('theme', 'dark') # 浏览器关闭即失效
    return resp

# 2. 读取 Cookie
@app.route('/get-cookie')
def get_cookie():
    # 使用 request.cookies 字典获取
    # 推荐使用 .get() 方法,避免 key 不存在时报 KeyError
    username = request.cookies.get('username', '匿名用户')
    theme = request.cookies.get('theme', 'light')

    return f'你好, {username}! 你的主题设置是: {theme}'

# 3. 删除 Cookie
@app.route('/delete-cookie')
def delete_cookie():
    resp = make_response('Cookie 已删除!')
    # 删除 Cookie 实际上是将它的过期时间设置为过去
    resp.delete_cookie('username')
    resp.delete_cookie('theme')
    return resp

2. 操作 Session ⭐ (核心重点)

在 Flask 中使用 Session 非常简单,它就像一个字典。但有一个绝对的前提条件必须配置 SECRET_KEY

前提配置:

纯文本
plaintext
app = Flask(__name__)
# 必须设置一个复杂且保密的密钥,用于对 Session 数据进行加密签名
app.config['SECRET_KEY'] = 'your-super-secret-key-here-change-in-production'

代码示例:模拟用户登录状态

纯文本
plaintext
from flask import Flask, session, redirect, url_for, request

app = Flask(__name__)
app.config['SECRET_KEY'] = 'super-secret-key-123'

# 1. 登录:写入 Session
@app.route('/login', methods=['GET', 'POST'])
def login():
    if request.method == 'POST':
        username = request.form.get('username')
        # 将数据存入 session 字典
        session['username'] = username
        session['is_logged_in'] = True
        return redirect(url_for('index'))

    return '''
        <form method="post">
            <input type="text" name="username" placeholder="Username">
            <input type="submit" value="Login">
        </form>
    '''

# 2. 首页:读取 Session
@app.route('/')
def index():
    # 使用 .get() 安全读取
    if session.get('is_logged_in'):
        return f'欢迎回来, {session.get("username")}! <a href="/logout">登出</a>'
    return '你还未登录,请 <a href="/login">登录</a>。'

# 3. 登出:删除 Session
@app.route('/logout')
def logout():
    # 移除特定 key
    session.pop('username', None)
    session.pop('is_logged_in', None)

    # 或者清空整个 session
    # session.clear() 

    return redirect(url_for('index'))

3. Flask Session 的“坑”与安全须知

因为 Flask 的 Session 本质上是加密签名的 Cookie,所以它继承了 Cookie 的所有物理限制和安全特性:

❌ 绝对不能做的事:

  1. 不要存储敏感信息:虽然数据被签名(无法篡改),但它是 Base64 编码的,用户可以轻松解码并看到内容(例如使用浏览器的开发者工具)。绝对不要存密码、身份证号、信用卡号!
  2. 不要存储大量数据:Cookie 的大小限制通常是 4KB。如果你在 Session 里存了一个包含几千条记录的列表,会导致请求头过大,浏览器直接报错。

✅ 安全最佳实践:

  1. SECRET_KEY 必须复杂:使用随机生成的长字符串,且不要提交到 Git。生产环境应通过环境变量读取。
  2. 开启安全标志(在配置中):
纯文本
plaintext
   # 仅通过 HTTPS 传输 Cookie
   app.config['SESSION_COOKIE_SECURE'] = True 
   # 禁止 JavaScript 读取 Cookie (防 XSS 攻击)
   app.config['SESSION_COOKIE_HTTPONLY'] = True 
   # 限制 Cookie 只能同源发送 (防 CSRF 攻击)
   app.config['SESSION_COOKIE_SAMESITE'] = 'Lax' 

4. 进阶:真正的“服务器端 Session”

如果你需要突破 4KB 的限制,或者绝对不想把任何数据发给客户端,你需要使用服务器端 Session

此时,Cookie 里只存一个随机的 session_id,真正的数据存储在服务器端的 Redis 或数据库中。

实现方法:使用官方扩展 Flask-Session

纯文本
plaintext
pip install Flask-Session redis
纯文本
plaintext
from flask import Flask, session
from flask_session import Session
import redis

app = Flask(__name__)

# 配置 Flask-Session 使用 Redis 作为后端
app.config['SESSION_TYPE'] = 'redis'
app.config['SESSION_REDIS'] = redis.from_url('redis://127.0.0.1:6379')
app.config['SECRET_KEY'] = 'super-secret-key'

# 初始化扩展
Session(app)

@app.route('/')
def index():
    # 用法与默认 Session 完全一样!
    session['huge_data'] = 'A' * 10000  # 现在可以存大数据了
    return 'Data stored in Redis!'

📝 总结

操作对象代码示例
读 Cookierequestrequest.cookies.get('key')
写 Cookieresponseresp = make_response(...)
resp.set_cookie('key', 'val')
删 Cookieresponseresp.delete_cookie('key')
读 Sessionsessionsession.get('key')
写 Sessionsessionsession['key'] = 'value'
删 Sessionsessionsession.pop('key', None)

掌握了 Cookie 和 Session,你的 Flask 应用就具备了“记忆”能力,可以实现用户登录、权限控制等核心功能了。

接下来,你想学习如何使用 Jinja2 模板引擎(让 HTML 页面动态化),还是直接挑战连接数据库 (Flask-SQLAlchemy)

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注