Skip to content

Django - Session 管理

虽然 Cookie 允许在客户端存储数据,但 Session 提供了一种在 服务器端 存储用户特定数据的机制。对于敏感信息而言,这种方式通常更安全,因为实际数据不驻留在用户的浏览器中。

Session 工作原理:

  1. 当用户首次访问使用 Session 的网站时,Django 会生成一个唯一的、随机的 会话 ID (Session ID)。
  2. Django 将此 Session ID 发送回用户的浏览器,通常存储在一个标准的 Cookie 中。
  3. 在同一用户的后续请求中,浏览器会将 Session ID Cookie 发送回 Django。
  4. Django 使用此 ID 在服务器端查找对应的 Session 数据(例如,在数据库、缓存或文件系统中)。
  5. 应用程序随后可以读取或写入与该特定用户 Session 相关的数据。

通过这种方式,客户端只存储了 Session ID;实际的 Session 数据(如用户 ID、购物车内容、用户偏好设置)仍然保留在服务器上。

在用 django-admin startproject 创建的新项目中,Django 的 Session 框架默认是启用的。它依赖于特定的中间件 (middleware) 和一个在 settings.py 中列出的应用 (app):

  1. 中间件 (Middleware): 确保 'django.contrib.sessions.middleware.SessionMiddleware' 存在于您的 MIDDLEWARE 设置中(通常放置在 UpdateCacheMiddleware 之后,如果使用站点范围缓存,则放置在 CommonMiddleware 之前,否则其确切位置不太关键,但通常在列表中间)。
MIDDLEWARE = [
# ...
'django.contrib.sessions.middleware.SessionMiddleware',
# ...
]
  1. 已安装应用 (Installed App): 确保 'django.contrib.sessions' 存在于您的 INSTALLED_APPS 设置中。
INSTALLED_APPS = [
# ...
'django.contrib.sessions',
# ...
]
  1. 数据库迁移 (Database Migrations): 如果您使用的是默认的基于数据库的 Session,则需要运行迁移 (migrate) 来创建必要的表 (django_session)。
python manage.py migrate

默认情况下,Django 将 Session 数据存储在数据库中(django_session 表)。您可以通过在 settings.py 中使用 SESSION_ENGINE 设置来改变此行为:

  • 'django.contrib.sessions.backends.db': 数据库(默认)。可靠,但在高负载下可能较慢。
  • 'django.contrib.sessions.backends.cache': 使用您的默认缓存后端 (cache backend)。更快,但如果缓存被清除,数据可能会丢失。
  • 'django.contrib.sessions.backends.cached_db': 同时写入数据库和缓存(写穿透缓存)。先从缓存读取,然后从数据库读取。一个很好的平衡。
  • 'django.contrib.sessions.backends.file': 将 Session 存储在指定目录 (SESSION_FILE_PATH) 的文件中。
  • 'django.contrib.sessions.backends.signed_cookies': 将所有 Session 数据直接存储在客户端 Cookie 中,经过加密签名。避免了服务器端存储的需求,但受限于 Cookie 大小,且如果签名密钥被泄露,存在潜在的安全隐患。

示例:使用缓存支持的 Session

settings.py
SESSION_ENGINE = 'django.contrib.sessions.backends.cache'

当 Session 中间件激活时,每个 HttpRequest 对象(视图函数中的第一个参数,通常命名为 request)都将拥有一个 session 属性。此属性的行为类似于 Python 字典。

让我们修改 Cookies 一章中的简单登录示例来使用 Session。

myapp/views.py
from django.shortcuts import render, redirect
from django.http import HttpResponse
from .forms import LoginForm # 假设存在 LoginForm
from datetime import datetime # 导入 datetime 模块
def login_session_view(request):
if request.method == 'POST':
form = LoginForm(request.POST)
if form.is_valid():
username = form.cleaned_data['username']
# 将用户名存储到 Session 中
request.session['username'] = username
request.session['login_time'] = str(datetime.now()) # 存储登录时间
# 设置 Session 过期时间(例如,30 分钟不活动后过期)
request.session.set_expiry(1800)
return redirect('session_status') # 重定向到状态页
else:
return render(request, 'login.html', {'form': form})
else:
form = LoginForm()
return render(request, 'login.html', {'form': form})
def session_status_view(request):
# 使用 .get() 安全地访问 Session 数据
username = request.session.get('username')
if username:
# 用户已通过 Session 登录
login_time = request.session.get('login_time', 'N/A')
expiry_age = request.session.get_expiry_age()
return render(request, 'loggedin.html', {
'username': username,
'login_time': login_time,
'expiry_seconds': expiry_age
})
else:
# 没有活动的 Session 或用户名未设置
return redirect('login_session') # 重定向回登录页
def logout_session_view(request):
# 完全清除 Session 数据
request.session.flush()
return render(request, 'logout_message.html')
# 在 myapp/urls.py 中添加 URL 模式:
# path('login/', views.login_session_view, name='login_session')
# path('status/', views.session_status_view, name='session_status')
# path('logout/', views.logout_session_view, name='logout_session')

关键 Session 操作:

  • 存储数据: request.session['my_key'] = 'my_value'
  • 检索数据: value = request.session.get('my_key', 'default_if_not_found')(使用 .get() 比 request.session['my_key'] 更安全)
  • 删除数据: del request.session['my_key'](如果键不存在会引发 KeyError)
  • 检查是否存在: 'my_key' in request.session
  • 清除所有 Session 数据: request.session.flush()(相当于注销用户)
  • 设置过期时间: request.session.set_expiry(value),其中 value 可以是秒数(整数)、datetime 对象,或者 0(浏览器关闭时过期),或者 None(使用全局设置)。
  • 获取过期信息: request.session.get_expiry_age()(剩余秒数),request.session.get_expiry_date()(datetime 对象)。
  • 检查是否设置浏览器关闭过期: request.session.get_expire_at_browser_close()(返回 True 或 False)。

您可以通过 settings.py 中的设置控制全局 Session 行为:

  • SESSION_COOKIE_AGE:Session Cookie 的默认生存期,以秒为单位(例如,1209600 表示 2 周)。
  • SESSION_COOKIE_HTTPONLY:设为 True(默认)以防止客户端 JavaScript 访问 Session Cookie。
  • SESSION_COOKIE_SECURE:如果您的网站只使用 HTTPS,则设为 True。
  • SESSION_COOKIE_SAMESITE:控制跨站点 Cookie 行为(默认是 ‘Lax’,选项还有 ‘Strict’ 或 ‘None’)。
  • SESSION_EXPIRE_AT_BROWSER_CLOSE:如果您希望 Session 在浏览器关闭时过期,则设为 True(会覆盖 SESSION_COOKIE_AGE)。
  • SESSION_SAVE_EVERY_REQUEST:如果为 True,则在每次请求时都会保存 Session,即使它未修改。默认是 False(仅在 Session 数据更改时保存),这样更高效。

Session 是在 Django 中构建有状态 Web 应用的基础,尤其对于处理用户认证和个性化体验至关重要。

进一步阅读: