# Token 共享机制 本项目与 JeecgBoot 前端共享登录态,可以实现无缝跳转。 ## 存储机制 ### 内存缓存优先 参考 JeecgBoot 前端实现,使用**内存缓存优先**机制: 1. **读取流程**: - 优先从内存缓存(Map)读取 - 内存未命中时从 localStorage 读取 - 读取后自动缓存到内存 2. **写入流程**: - 同时写入内存缓存和 localStorage - 保证数据一致性 3. **性能优势**: - 减少 localStorage 访问次数 - 提高频繁读取场景的性能 - 减少 JSON 序列化/反序列化开销 ### LocalStorage Keys **完全兼容 JeecgBoot 的 Persistent 缓存结构!** 主 Key:`产业带独立站供应商管理系统__PRODUCTION__1.0.0__COMMON__LOCAL__KEY__` 这个 key 存储一个 JSON 对象,包含以下子 key: | 子 Key | 说明 | 数据结构 | |--------|------|---------| | `TOKEN__` | 访问令牌 | `{value: "token", alive: 604800000, time: 1234567890}` | | `USER__INFO__` | 用户信息 | `{value: {...}, alive: 604800000, time: 1234567890}` | | `TENANT_ID` | 租户 ID | `{value: "1", alive: 604800000, time: 1234567890}` | | `ROLES__KEY__` | 角色信息 | `{value: [...], alive: 604800000, time: 1234567890}` | **实际存储示例(两层嵌套结构):** ```json { "value": { "TOKEN__": { "value": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...", "alive": 604800000, "time": 1765349535641 }, "USER__INFO__": { "value": { "username": "admin", "realname": "管理员" }, "alive": 604800000, "time": 1765349535731 }, "LOGIN__INFO__": { "value": { "token": "...", "userInfo": {...} }, "alive": 604800000, "time": 1765349536334 } }, "time": 1764744736334, "expire": 1765349536334 } ``` **注意:** JeecgBoot 使用两层嵌套结构: 1. 外层 `value` 包含所有子 key 2. 每个子 key 又有自己的 `value` 存储实际数据 ## 使用方法 ### 1. 登录时保存 Token ```typescript import { setToken, setUserInfo } from '@/utils/auth'; // 登录成功后 const result = await authApi.login({ username, password, captcha }); // 保存 token setToken(result.token); // 保存用户信息 setUserInfo(result.userInfo); ``` ### 2. 请求时携带 Token HTTP 拦截器会自动从 localStorage 读取 token 并添加到请求头: ```typescript // 自动添加以下 headers { "X-Access-Token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...", "Authorization": "Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..." } ``` ### 3. 登出时清除 Token ```typescript import { clearAuth } from '@/utils/auth'; // 清除所有认证信息 clearAuth(); // 跳转到登录页 navigate('/login'); ``` ### 4. 检查登录状态 ```typescript import { isAuthenticated } from '@/utils/auth'; if (!isAuthenticated()) { // 未登录,跳转到登录页 navigate('/login'); } ``` ## 跨应用跳转 由于使用相同的 localStorage key,可以实现以下场景: ### 从 React 应用跳转到 JeecgBoot 前端 ```typescript // 直接跳转,token 会自动共享 window.location.href = 'http://jeecg-boot-frontend.com/dashboard'; ``` ### 从 JeecgBoot 前端跳转到 React 应用 ```javascript // 直接跳转,token 会自动共享 window.location.href = 'http://react-app.com/spaces/content-model'; ``` ## Token 刷新 当 token 过期(401 错误)时,系统会自动: 1. 清除所有认证信息(`clearAuth()`) 2. 显示"登录已过期"提示 3. 1.5 秒后跳转到登录页 ## 安全注意事项 1. **Token 存储**:使用 localStorage 存储,注意 XSS 攻击防护 2. **Token 传输**:使用 HTTPS 协议传输 3. **Token 过期**:后端应设置合理的过期时间 4. **敏感操作**:重要操作应要求二次验证 ## API 工具函数 ### auth.ts 所有函数都支持内存缓存优先机制: ```typescript // ========== Token 管理 ========== // 获取 token(优先从内存读取) getToken(): string | null // 设置 token(同时写入内存和 localStorage) setToken(token: string): void // 移除 token(同时清除内存和 localStorage) removeToken(): void // ========== 用户信息管理 ========== // 获取用户信息 getUserInfo(): T | null // 设置用户信息 setUserInfo(userInfo: any): void // 移除用户信息 removeUserInfo(): void // ========== 登录信息管理 ========== // 获取登录信息(JeecgBoot 兼容) getLoginInfo(): T | null // 设置登录信息 setLoginInfo(loginInfo: any): void // 移除登录信息 removeLoginInfo(): void // ========== 租户管理 ========== // 获取租户 ID getTenantId(): string | null // 设置租户 ID setTenantId(tenantId: string): void // 移除租户 ID removeTenantId(): void // ========== 认证状态 ========== // 检查是否已登录 isAuthenticated(): boolean // 清除所有认证信息 clearAuth(): void // 清空所有缓存(包括内存和浏览器) clearAllAuthCache(): void // ========== 动态缓存(JeecgBoot 兼容)========== // 设置动态 key 缓存 setCacheByDynKey(key: string, value: any): void // 获取动态 key 缓存 getCacheByDynKey(key: string): T | null // 移除动态 key 缓存 removeCacheByDynKey(key: string): void ``` ### 性能说明 ```typescript // 第一次读取:从 localStorage 读取并缓存到内存 const token1 = getToken(); // 访问 localStorage // 后续读取:直接从内存读取,速度更快 const token2 = getToken(); // 从内存读取(快) const token3 = getToken(); // 从内存读取(快) // 写入:同时更新内存和 localStorage setToken('new-token'); // 更新两层缓存 // 清除:同时清除内存和 localStorage clearAuth(); // 清除所有认证信息 ``` ## 与 JeecgBoot 的兼容性 | 特性 | JeecgBoot | React 应用 | 兼容性 | |------|-----------|-----------|--------| | Token Key | `ACCESS_TOKEN` | `ACCESS_TOKEN` | ✅ 完全兼容 | | Token Header | `X-Access-Token` | `X-Access-Token` | ✅ 完全兼容 | | 用户信息 Key | `USER_INFO` | `USER_INFO` | ✅ 完全兼容 | | 租户 ID Key | `TENANT_ID` | `TENANT_ID` | ✅ 完全兼容 | | 401 处理 | 清除 token 并跳转 | 清除 token 并跳转 | ✅ 完全兼容 | ## 示例场景 ### 场景 1:用户在 React 应用登录 1. 用户在 React 应用登录 2. Token 保存到 `localStorage.ACCESS_TOKEN` 3. 用户点击链接跳转到 JeecgBoot 前端 4. JeecgBoot 前端读取 `localStorage.ACCESS_TOKEN` 5. 用户无需重新登录,直接访问 ### 场景 2:用户在 JeecgBoot 前端登录 1. 用户在 JeecgBoot 前端登录 2. Token 保存到 `localStorage.ACCESS_TOKEN` 3. 用户点击链接跳转到 React 应用 4. React 应用读取 `localStorage.ACCESS_TOKEN` 5. 用户无需重新登录,直接访问 ### 场景 3:Token 过期 1. 用户在任一应用中操作 2. Token 过期,后端返回 401 3. 应用清除所有认证信息 4. 显示"登录已过期"提示 5. 跳转到登录页