令牌与会话管理(中文译文)
原始 DeepWiki 页面:https://deepwiki.com/open-webui/open-webui/11.5-token-and-session-management
翻译时间:2026-06-09T16:10:42.109Z
翻译模型:deepseek-chat
原文字符数:10862
项目:Open WebUI (open-webui)
---
Token 和会话管理
相关源文件
以下文件被用作生成此 Wiki 页面的上下文:
backend/open_webui/config.pybackend/open_webui/env.pybackend/open_webui/main.pybackend/open_webui/routers/auths.pybackend/open_webui/socket/main.pybackend/open_webui/socket/utils.pybackend/open_webui/tasks.pybackend/open_webui/test/util/test_redis.pybackend/open_webui/utils/auth.pybackend/open_webui/utils/oauth.pybackend/open_webui/utils/rate_limit.pybackend/open_webui/utils/redis.py
本文档介绍 Open WebUI 中的会话和 Token 管理系统,包括 JWT Token 的创建与验证、基于 Redis 的 Token 撤销、OAuth 会话存储,以及用于实时功能的分布式会话池。
---
概述
Open WebUI 实现了多层认证与会话系统:
- JWT Token 用于无状态认证,可选配基于 Redis 的撤销机制。
backend/open_webui/utils/auth.py:201-212 - API 密钥 用于程序化访问(格式:
sk-{uuid})。backend/open_webui/utils/auth.py:262-264 - HTTP Cookie 用于基于浏览器的会话持久化。
backend/open_webui/routers/auths.py:124-135 - OAuth 会话 存储在服务端,Token 数据经过加密。
backend/open_webui/utils/oauth.py:193-205 - 分布式会话池 用于跨多个节点的实时 WebSocket 状态管理。
backend/open_webui/socket/main.py:123-128
该系统同时支持无状态(JWT)和有状态(Redis 撤销、OAuth 会话)模式,以确保安全性和可扩展性。
---
JWT Token 系统
Token 创建
JWT Token 通过 create_token() 函数创建。该函数为每个 Token 生成唯一的 jti(JWT ID),以支持细粒度的撤销操作。backend/open_webui/utils/auth.py:201-212
Token 创建流程
graph TB
subgraph "Token 创建流程"
SignIn["create_session_response()<br/>[auths.py:100]"]
CreateToken["create_token(data, expires_delta)<br/>[auth.py:201]"]
JWTEncode["jwt.encode(payload, SESSION_SECRET, ALGORITHM)<br/>[auth.py:211]"]
SetCookie["response.set_cookie('token', ...)<br/>[auths.py:127]"]
SignIn --> CreateToken
CreateToken --> |"添加 exp, jti, iat"| JWTEncode
JWTEncode --> SetCookie
end
subgraph "Token 载荷结构"
Payload["Token 载荷"]
UserID["id: user.id"]
Expiration["exp: datetime.now(UTC) + expires_delta"]
JTI["jti: str(uuid.uuid4())"]
IAT["iat: datetime.now(UTC)"]
Payload --> UserID
Payload --> Expiration
Payload --> JTI
Payload --> IAT
end
CreateToken -.-> Payload
来源: backend/open_webui/utils/auth.py:201-212,backend/open_webui/routers/auths.py:100-149
Token 结构
每个 JWT Token 包含以下声明:
| 声明 | 描述 | 来源 |
|---|---|---|
id | 用户标识符 | backend/open_webui/utils/auth.py:202 |
exp | 过期时间戳(Unix 纪元) | backend/open_webui/utils/auth.py:205-206 |
jti | JWT ID(UUID v4),用于撤销 | backend/open_webui/utils/auth.py:208 |
iat | 签发时间戳 | backend/open_webui/utils/auth.py:208 |
Token 使用 HS256 算法和 WEBUI_SECRET_KEY 进行签名。backend/open_webui/utils/auth.py:51-52
来源: backend/open_webui/utils/auth.py:201-212,backend/open_webui/env.py:39
Token 验证
Token 验证在 get_current_user() 中执行。如果 Redis 可用,则通过 is_valid_token() 进行撤销检查。backend/open_webui/utils/auth.py:223-237,backend/open_webui/utils/auth.py:277-372
Token 验证序列
sequenceDiagram
participant Client
participant Middleware as "get_current_user()<br/>[auth.py:277]"
participant Decoder as "decode_token()<br/>[auth.py:215]"
participant Redis as "Redis<br/>(如果可用)"
participant DB as "Users.get_user_by_id()"
Client->>Middleware: 携带 Authorization 头或 Cookie 的请求
alt API 密钥认证
Middleware->>Middleware: 检查 token 是否以 'sk-' 开头
Middleware->>DB: Users.get_user_by_api_key(token)
DB-->>Middleware: User 对象
Middleware-->>Client: 认证通过
else JWT 认证
Middleware->>Decoder: decode_token(token)
Decoder-->>Middleware: {"id": "...", "jti": "...", "exp": ...}
opt Redis 可用
Middleware->>Middleware: is_valid_token(request, decoded)<br/>[auth.py:223]
Middleware->>Redis: GET {REDIS_KEY_PREFIX}:auth:token:{jti}:revoked
Redis-->>Middleware: null(未撤销)
end
Middleware->>DB: Users.get_user_by_id(data["id"])
DB-->>Middleware: User 对象
Middleware-->>Client: 认证通过的用户
end
来源: backend/open_webui/utils/auth.py:215-220,backend/open_webui/utils/auth.py:223-235,backend/open_webui/utils/auth.py:277-372
---
Token 撤销
Open WebUI 通过 Redis 实现了两种撤销机制:按 Token 撤销和按用户撤销。backend/open_webui/utils/auth.py:223-237
基于 Redis 的撤销架构
graph LR
subgraph "Token 生命周期"
Create["Token 已创建<br/>jti: str(uuid.uuid4())"]
Use["Token 已使用<br/>通过 jti 验证"]
Signout["用户登出<br/>[auths.py:756]"]
Revoke["invalidate_token(request, token)<br/>[auth.py:238]"]
Create --> Use
Use --> Signout
Signout --> Revoke
end
subgraph "Redis 存储"
RedisKey["键: {REDIS_KEY_PREFIX}:auth:token:{jti}:revoked<br/>值: '1'<br/>TTL: exp - now"]
end
subgraph "验证"
Check["is_valid_token(request, decoded)<br/>[auth.py:223]"]
RedisGet["await request.app.state.redis.get(key)"]
Decision{"已撤销?"}
Check --> RedisGet
RedisGet --> Decision
Decision -->|"是(键存在)"| Reject["返回 False"]
Decision -->|"否(键为 null)"| Accept["返回 True"]
end
Revoke --> RedisKey
Use --> Check
来源: backend/open_webui/utils/auth.py:223-235,backend/open_webui/utils/auth.py:238-256
实现细节
- 按 Token 撤销: 用户登出时,
invalidate_token()计算 JWT 的剩余 TTL(exp - now),并将jti以该过期时间存储到 Redis 中。backend/open_webui/utils/auth.py:238-256 - 按用户撤销: 用于 OIDC 反向通道登出。在 Redis 中为用户存储一个
revoked_at时间戳。任何iat(签发时间)小于或等于revoked_at的 Token 都会被拒绝。backend/open_webui/utils/auth.py:237
来源: backend/open_webui/utils/auth.py:238-256,backend/open_webui/env.py:79
---
WebSocket 会话管理
当 WEBSOCKET_MANAGER 设置为 "redis" 时,Open WebUI 使用分布式会话池来跟踪跨多个后端节点的活跃用户连接。backend/open_webui/socket/main.py:65-72
会话池与清理
系统在 Redis 中维护一个 SESSION_POOL,它是一个 RedisDict,将套接字 ID(sid)映射到用户元数据。backend/open_webui/socket/main.py:123-128
孤立会话清理 周期性任务 periodic_session_pool_cleanup() 会清理在 SESSION_POOL_TIMEOUT(120 秒)内未发送心跳的会话。backend/open_webui/socket/main.py:173-194
- 加锁: 使用
RedisLock确保集群中只有一个节点执行清理操作。backend/open_webui/socket/main.py:147-156 - 回收: 遍历
SESSION_POOL.keys(),删除now - last_seen_at > 120的条目。backend/open_webui/socket/main.py:186-190
来源: backend/open_webui/socket/main.py:101-164,backend/open_webui/socket/main.py:173-194,backend/open_webui/socket/utils.py:9-43
---
OAuth 会话管理
OAuth 会话将提供商特定的 Token(访问令牌、刷新令牌)存储在服务端,并使用 Fernet 算法进行静态加密。backend/open_webui/utils/oauth.py:193-205
Token 加密
加密密钥源自 OAUTH_CLIENT_INFO_ENCRYPTION_KEY。如果密钥长度不是所需的 44 字节,则通过 SHA256 哈希并 base64 编码,以满足 Fernet 的要求。backend/open_webui/utils/oauth.py:180-191
- 加密:
encrypt_data(data)在加密前将 Token 字典序列化为 JSON。backend/open_webui/utils/oauth.py:193-201 - 解密:
decrypt_data(data)执行反向操作。backend/open_webui/utils/oauth.py:204-210
来源: backend/open_webui/utils/oauth.py:180-210,backend/open_webui/env.py:77
---
配置参考
环境变量
| 变量 | 类型 | 默认值 | 描述 |
|---|---|---|---|
WEBUI_SECRET_KEY | 字符串 | "t0p-s3cr3t" | JWT 签名密钥。backend/open_webui/utils/auth.py:51 |
JWT_EXPIRES_IN | 持续时间 | "60m" | Token 过期时长。backend/open_webui/routers/auths.py:114 |
REDIS_URL | 字符串 | "" | 用于 Token 撤销和会话管理的连接 URL。backend/open_webui/env.py:27 |
WEBSOCKET_MANAGER | 字符串 | "memory" | 设置为 "redis" 以支持分布式多节点。backend/open_webui/socket/main.py:65 |
OAUTH_CLIENT_INFO_ENCRYPTION_KEY | 字符串 | 用于加密 OAuth 会话数据的密钥。backend/open_webui/env.py:77 |
来源: backend/open_webui/env.py:27-79,backend/open_webui/socket/main.py:25-41
Redis 键模式
| 键模式 | 用途 | 来源 |
|---|---|---|
{prefix}:auth:token:{jti}:revoked | 已列入黑名单的 JWT Token | backend/open_webui/utils/auth.py:233 |
{prefix}:session_pool | 活跃 WebSocket 会话元数据 | backend/open_webui/socket/main.py:123 |
{prefix}:usage_pool | 实时模型使用跟踪 | backend/open_webui/socket/main.py:129 |
{prefix}:ydoc:documents:{id}:updates | 协作笔记编辑更新 | backend/open_webui/socket/utils.py:130-141 |
来源: backend/open_webui/socket/main.py:116-142,backend/open_webui/socket/utils.py:124-141