c55c4a140b
A1/A3 客户端令牌链路(服务端守卫已能按 JWT 鉴权,缺口在客户端不带身份) - 前端:新增 user-token-bridge(纯逻辑,值变化才推送)+ user-token-sync(启动安装, pywebviewready/storage/60s 轮询补推),main.ts 接入;桥接口补 set_user_token - 客户端:新增 crawler_core/user_token.py(持有 + 对自家 Java 端点注入 Authorization: Bearer <jwt>,Session.request 包装,第三方域名不注入、已有头不覆盖、 登出清空、SHUFUAI_DISABLE_USER_TOKEN_HOOK 可关);main.py 暴露桥方法并在启动安装钩子 - 服务端:守卫契约测试补 5 个用户态前缀用例(开关关闭放行 / 打开后匿名 401 / 用户令牌通过 / 内部令牌仍放行 / /api/ziniao 第二层) - 翻开关的前置条件(客户端铺开后置 aiimage.security.user-tool-guard-enabled=true)写入报告 C8 快照 JSON 写入节流 - 读端改以 biz_task_result_item 行为准、JSON 仅兜底(历史任务 JSON 仍是唯一副本时可用) - 整档 JSON 改 30s 节流写,终态路径 force 立即写;新增 2 个契约测试钉住语义 验证:mvn test 2888 全绿;npm test 741 全绿;user_token 钩子自测(注入/归一/第三方跳过/不覆盖/登出)通过
61 lines
1.6 KiB
TypeScript
61 lines
1.6 KiB
TypeScript
import { getPywebviewApi } from '@/shared/bridges/pywebview'
|
|
import { setUserTokenPushTarget, syncUserTokenToBridge } from '@/shared/auth/user-token-bridge'
|
|
|
|
/**
|
|
* 把登录态令牌持续同步给桌面端 Python(A1/A3)。
|
|
*
|
|
* 触发点:应用启动(桥可能未就绪,监听 pywebviewready 后补推)、localStorage 变化(登录/登出)、
|
|
* 以及每 60 秒兜底轮询(同标签页内 localStorage 变化不触发 storage 事件)。
|
|
* 网页形态(无桥)静默跳过。
|
|
*/
|
|
|
|
const AUTH_TOKEN_KEY = 'aiimage_auth_token'
|
|
const POLL_INTERVAL_MS = 60_000
|
|
|
|
let installed = false
|
|
|
|
function readToken(): string {
|
|
try {
|
|
return window.localStorage.getItem(AUTH_TOKEN_KEY) || ''
|
|
} catch {
|
|
return ''
|
|
}
|
|
}
|
|
|
|
function pushNow(): void {
|
|
syncUserTokenToBridge(readToken())
|
|
}
|
|
|
|
export function installUserTokenSync(): void {
|
|
if (installed || typeof window === 'undefined') {
|
|
return
|
|
}
|
|
installed = true
|
|
|
|
const apply = () => {
|
|
const api = getPywebviewApi()
|
|
setUserTokenPushTarget(
|
|
api && typeof api.set_user_token === 'function'
|
|
? {
|
|
push: (value: string) => {
|
|
void Promise.resolve(api.set_user_token?.(value)).catch(() => {
|
|
/* 桥调用失败不影响页面 */
|
|
})
|
|
},
|
|
}
|
|
: null,
|
|
)
|
|
pushNow()
|
|
}
|
|
|
|
// 桥可能晚于脚本就绪:先尝试一次,再在 ready 事件与轮询里补
|
|
apply()
|
|
window.addEventListener('pywebviewready', apply)
|
|
window.addEventListener('storage', (event) => {
|
|
if (!event.key || event.key === AUTH_TOKEN_KEY) {
|
|
pushNow()
|
|
}
|
|
})
|
|
window.setInterval(pushNow, POLL_INTERVAL_MS)
|
|
}
|