agentic_huge_data_base / wiki
页面 Open WebUI · 11.5 令牌与会话管理·DeepWiki 中文全文译文

11.5 · 令牌与会话管理(Token and Session Management)

多模型对话工作台与知识应用入口 · 本章是 Open WebUI DeepWiki 中文译文的独立章节页,保留原始链接、源码锚点、模块标签和章节层级。

项目Open WebUI 章节11.5 状态全文译文 模块认证、权限与安全、系统架构、测试、发布与运维、接口与服务契约
源码线索
  • backend/open_webui/config.py
  • backend/open_webui/env.py
  • backend/open_webui/main.py
  • backend/open_webui/routers/auths.py
  • backend/open_webui/socket/main.py
  • backend/open_webui/socket/utils.py
  • backend/open_webui/tasks.py
  • backend/open_webui/test/util/test_redis.py
  • backend/open_webui/utils/auth.py
  • backend/open_webui/utils/oauth.py
模块标签
  • 认证、权限与安全
  • 系统架构
  • 测试、发布与运维
  • 接口与服务契约
  • 界面与交互

中文译文

令牌与会话管理(中文译文)

原始 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.py
  • backend/open_webui/env.py
  • backend/open_webui/main.py
  • backend/open_webui/routers/auths.py
  • backend/open_webui/socket/main.py
  • backend/open_webui/socket/utils.py
  • backend/open_webui/tasks.py
  • backend/open_webui/test/util/test_redis.py
  • backend/open_webui/utils/auth.py
  • backend/open_webui/utils/oauth.py
  • backend/open_webui/utils/rate_limit.py
  • backend/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-212backend/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
jtiJWT 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-212backend/open_webui/env.py:39

Token 验证

Token 验证在 get_current_user() 中执行。如果 Redis 可用,则通过 is_valid_token() 进行撤销检查。backend/open_webui/utils/auth.py:223-237backend/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-220backend/open_webui/utils/auth.py:223-235backend/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-235backend/open_webui/utils/auth.py:238-256

实现细节
  1. 按 Token 撤销: 用户登出时,invalidate_token() 计算 JWT 的剩余 TTL(exp - now),并将 jti 以该过期时间存储到 Redis 中。backend/open_webui/utils/auth.py:238-256
  2. 按用户撤销: 用于 OIDC 反向通道登出。在 Redis 中为用户存储一个 revoked_at 时间戳。任何 iat(签发时间)小于或等于 revoked_at 的 Token 都会被拒绝。backend/open_webui/utils/auth.py:237

来源: backend/open_webui/utils/auth.py:238-256backend/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

  1. 加锁: 使用 RedisLock 确保集群中只有一个节点执行清理操作。backend/open_webui/socket/main.py:147-156
  2. 回收: 遍历 SESSION_POOL.keys(),删除 now - last_seen_at > 120 的条目。backend/open_webui/socket/main.py:186-190

来源: backend/open_webui/socket/main.py:101-164backend/open_webui/socket/main.py:173-194backend/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-210backend/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-79backend/open_webui/socket/main.py:25-41

Redis 键模式
键模式用途来源
{prefix}:auth:token:{jti}:revoked已列入黑名单的 JWT Tokenbackend/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-142backend/open_webui/socket/utils.py:124-141