Flask - Sessions
Flask – 会话 (Sessions)
Section titled “Flask – 会话 (Sessions)”HTTP 是一种无状态协议(stateless protocol),意味着客户端向服务器发出的每个请求都是独立处理的。服务器本身不保留与同一客户端先前交互的记忆。为了在多个请求之间维护特定用户的信息(例如,保持用户登录状态、存储购物车内容),我们使用会话(sessions)。
与直接将数据存储在用户浏览器中的 Cookie 不同,Flask 默认的会话实现使用的是签名 Cookie(signed cookies)。这意味着会话数据本身(如用户名或用户 ID)存储在发送到客户端浏览器的 Cookie 中,但它是使用秘密密钥(secret key)由服务器进行加密签名的。这个签名允许服务器验证会话数据是否已被客户端篡改。
由于数据存储在客户端(在签名 Cookie 中),这种方法避免了为简单的会话数据进行服务器端存储的需求,使其具有可扩展性。然而,这也意味着你不应该直接在会话中存储大量数据或高度敏感的信息,因为 Cookie 有大小限制,并且数据(尽管已签名)对客户端仍然是可见的。
要在 Flask 中使用会话 (sessions),你需要:
- 设置
SECRET_KEY: 这对于安全地签署会话 Cookie 来说绝对至关重要。它应该是一个长、随机且不可预测的字符串,并且必须保密。在生产环境中,应从环境变量或配置管理系统加载它,切勿直接硬编码在源代码中。 - 导入并使用
session对象: Flask 通过从flask导入的session对象提供会话功能。这个对象行为类似于 Python 字典。
设置会话变量很简单:
from flask import session
# 示例:用户成功登录后存储用户名session['username'] = 'admin'读取会话变量:
# 检查用户是否已登录if 'username' in session: username = session['username'] print(f"User {username} is logged in.")else: print("User is not logged in.")移除会话变量(例如,在注销时):
# 从会话中移除 'username',如果不存在则返回 Nonesession.pop('username', None)我们来看一个简单的登录/注销示例:
from flask import Flask, session, redirect, url_for, request, render_template_string
app = Flask(__name__)
# IMPORTANT: Set a strong, random secret key!# In a real app, load this from config/environment variable.app.config['SECRET_KEY'] = 'your-very-secure-and-random-secret-key'
# Simple in-memory user store for demonstrationusers = {'admin': 'password123'}
@app.route('/')def index(): if 'username' in session: username = session['username'] return f''' Logged in as **{username}**<br> <a href="{url_for('logout')}">Click here to log out</a> ''' return f''' You are not logged in.<br> <a href="{url_for('login')}">Click here to log in</a> '''
@app.route('/login', methods=['GET', 'POST'])def login(): if request.method == 'POST': submitted_user = request.form.get('username') submitted_pass = request.form.get('password')
# Basic validation (replace with proper password hashing in real apps!) if submitted_user in users and users[submitted_user] == submitted_pass: session['username'] = submitted_user return redirect(url_for('index')) else: # Invalid credentials, show form again with error (optional) error = 'Invalid username or password' return render_template_string(LOGIN_FORM, error=error)
# For GET request, just show the login form return render_template_string(LOGIN_FORM, error=None)
# Define the login form as a multi-line string constantLOGIN_FORM = """<!doctype html><title>Login</title><h1>Login</h1>{% if error %}<p style="color:red;">{{ error }}</p>{% endif %}<form method="post"> <p>Username: <input type=text name=username></p> <p>Password: <input type=password name=password></p> <p><input type=submit value=Login></p></form>"""
@app.route('/logout')def logout(): # Remove the username from the session if it's there session.pop('username', None) return redirect(url_for('index'))
if __name__ == '__main__': app.run(debug=True)此示例的工作原理:
/(index): 检查session中是否存在username。如果存在,则显示欢迎消息和注销链接。如果不存在,则显示登录链接。/login(GET): 显示一个简单的 HTML 登录表单(为简化起见,在LOGIN_FORM字符串中定义并使用render_template_string渲染;通常你会使用单独的模板文件)。/login(POST): 从提交的表单 (request.form) 中获取用户名和密码。它对users字典执行非常基础的检查(在实际应用中,你必须安全地哈希密码)。如果凭据有效,它将username存储在session中并重定向到首页 (/)。如果无效,它会重新显示带有错误的表单。/logout: 使用session.pop()从session中移除username并重定向到首页。SECRET_KEY: 使 Flask 能够安全地签署会话 Cookie。
运行此应用程序(python app.py)并访问 http://localhost:5000/。你会看到“未登录”的消息。点击登录链接,输入“admin”和“password123”,然后提交。你将被重定向回 /,现在显示“以 admin 身份登录”的消息。点击注销链接将清除会话,使你返回“未登录”状态。
替代会话接口: 尽管 Flask 默认的签名 Cookie 会话很方便,但它并非适用于所有情况(例如,存储大量数据、需要服务器端失效)。Flask-Session 等 Flask 扩展允许你配置不同的会话后端,如 Redis、Memcached、SQLAlchemy(数据库)或文件系统,这些后端将会话数据存储在服务器端,而只向客户端发送一个会话 ID Cookie。