7.5 KiB
7.5 KiB
| title | date | category | module | problem_type | component | symptoms | root_cause | resolution_type | severity | tags | |||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| JWT secret 未设置导致 dev mode user_id 丢失 + reload 登录失效 | 2026-06-28 | docs/solutions/integration-issues | server/auth, server/app, tools/calendar_tool, frontend/stores/auth | integration_issue | authentication |
|
config_error | config_change | critical |
|
JWT secret 未设置导致 dev mode user_id 丢失 + reload 登录失效
Problem
用户报告4个问题:(1) 启动后出现一堆测试对话且无法删除;(2) 要求创建下周一日历事件,agent 回复已完成但日历里看不到;(3) 日历默认周日开始;(4) reload 后跳回登录页。深入调查发现问题2和4同根同源:AGENTKIT_JWT_SECRET 从未设置,触发 dev mode 一系列连锁反应。
Symptoms
- 日历事件数据不一致:calendar.db 中事件
user_id="default"/"zhangsan"(LLM hallucinate),但/calendar/events路由用user_id=None查询 → 返回空列表 - reload 登录失效:服务器重启后,之前签发的 refresh token 全部失效,前端
startupCheck→whoami(refresh)→ 401 →startupState='invalid'→ 跳/login - AuthMiddleware dev mode:所有请求
current_user={"user_id": None, "username": "dev", "role": "admin"} - CalendarTool schema 要求 LLM 提供 user_id:LLM 不知道真实值,hallucinate 假值写入 DB
What Didn't Work
- 前次"修复"日历 401:在 AuthMiddleware dev mode 分支添加 synthetic dev user(
user_id=None),解决了 401 但引入了user_id=None数据不一致问题——治标不治本 - 前次"修复"登录状态:在 auth.ts 注册4个 token provider,但未解决 refresh token 跨重启失效的根本问题
- 假设 API 删除失败:curl 直接测试 DELETE 端点返回 200,DB 行数减少——API 正常,问题是预存测试数据 + 前端视觉复活
Solution
核心修复:设置持久化 JWT secret
在 .env 中添加(.env 已被 gitignore,不会泄露):
# 生成持久化 secret
python3 -c "import secrets; print(secrets.token_urlsafe(48))"
# 写入 .env
AGENTKIT_JWT_SECRET=<generated_secret>
这一步同时解决问题2(AuthMiddleware 退出 dev mode,current_user.user_id 从 JWT payload 获取真实值)和问题4(refresh token 跨重启持久化)。
CalendarTool 注入真实 user_id
calendar_tool.py 修改:
# 之前:schema 要求 LLM 提供 user_id,LLM 会 hallucinate
"required": ["action", "user_id"],
# 之后:移除 user_id from required,改用注入的 default_user_id
def __init__(self, calendar_service, default_user_id: str | None = None):
...
self._default_user_id = default_user_id
def _resolve_user_id(self, kwargs) -> str | None:
provided = kwargs.get("user_id")
if provided and isinstance(provided, str) and provided.strip():
return provided
return self._default_user_id
app.py 在 lifespan 中查询 admin 用户并注入:
# 查询第一个 active admin 用户作为 default_user_id
async with aiosqlite.connect(str(DEFAULT_AUTH_DB_PATH)) as db:
db.row_factory = aiosqlite.Row
cur = await db.execute(
"SELECT id FROM users WHERE is_active = 1 "
"ORDER BY CASE role WHEN 'admin' THEN 0 ELSE 1 END, created_at LIMIT 1"
)
row = await cur.fetchone()
if row is not None:
default_cal_user_id = str(row["id"])
calendar_tool = CalendarTool(
calendar_service=cal_service,
default_user_id=default_cal_user_id,
)
CalendarGrid firstDay 配置
CalendarGrid.vue 添加 firstDay: 1。
数据清理
# 清理测试对话
sqlite3 ~/.agentkit/conversations.db "DELETE FROM messages; DELETE FROM conversations;"
# 修复 calendar.db 中已存在的 hallucinate user_id
sqlite3 data/calendar.db "UPDATE calendar_events SET user_id = '<admin_user_id>' WHERE user_id IN ('default', 'zhangsan')"
Why This Works
根因因果链:
AGENTKIT_JWT_SECRET未设置 →get_jwt_secret()返回 None- app.py:812-837 中
explicit_jwt_secret or ""传给 AuthMiddleware →jwt_secret=""→_is_dev_mode()=True - dev mode 下
get_or_create_jwt_secret()每次进程启动生成新的 ephemeral secret(不持久化) - 问题4:服务器重启 → 新 ephemeral secret → 旧 refresh token 签名不匹配 → whoami 401 → 跳登录页
- 问题2:dev mode 下
current_user.user_id=None,CalendarTool 由 LLM hallucinateuser_id="default",UI 路径用None查询不匹配 → 日历看不到事件
设置 AGENTKIT_JWT_SECRET 后:
- AuthMiddleware 收到真实 secret →
_is_dev_mode()=False→ JWT 验证启用 →current_user.user_id从 payload 获取 get_jwt_secret()返回持久化 secret → 跨重启一致 → refresh token 持久有效
Prevention
- 环境变量检查:在
app.py启动时检查AGENTKIT_JWT_SECRET是否设置,未设置时打印明显警告(当前 dev mode 日志不够醒目) - e2e 测试覆盖:添加 e2e 测试覆盖以下场景:
- 服务器重启后 reload 页面,验证登录状态保持
- agent 创建日历事件后,UI 能看到该事件(数据一致性 +
calendar_event_createdWS 消息到达前端,详见 calendar-agent-create-no-refresh.md) - 无效 token 返回 401(非 dev mode 验证)
- CalendarTool user_id 来源:多用户场景需通过 agent 框架 contextvar 传递 per-request user_id,当前
default_user_id是 dev 模式单用户简化(代码中已标注ponytail:注释) - 配置审计:
.env.example应列出AGENTKIT_JWT_SECRET并说明必须设置
Related Issues
同一症状("agent 创建日历事件后 UI 看不到")现已记录三个不同的根因,调查时需同时排查:
- 日历能力缺失修复 + UI 布局优化 — 前次日历问题(CalendarTool 接入 ReAct),本次是认证配置导致的 user_id 不匹配,同一领域不同根因
- Calendar events created via agent chat do not refresh the calendar UI —
CalendarService.create_event创建成功后未广播calendar_event_createdWS 消息(第三个根因,2026-06-29 记录) - Portal 平台安全可靠性修复 — 认证相关修复