TOKEN_SHARING.md 6.9 KB

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}

实际存储示例(两层嵌套结构):

{
  "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

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 并添加到请求头:

// 自动添加以下 headers
{
  "X-Access-Token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
  "Authorization": "Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
}

3. 登出时清除 Token

import { clearAuth } from '@/utils/auth';

// 清除所有认证信息
clearAuth();

// 跳转到登录页
navigate('/login');

4. 检查登录状态

import { isAuthenticated } from '@/utils/auth';

if (!isAuthenticated()) {
  // 未登录,跳转到登录页
  navigate('/login');
}

跨应用跳转

由于使用相同的 localStorage key,可以实现以下场景:

从 React 应用跳转到 JeecgBoot 前端

// 直接跳转,token 会自动共享
window.location.href = 'http://jeecg-boot-frontend.com/dashboard';

从 JeecgBoot 前端跳转到 React 应用

// 直接跳转,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

所有函数都支持内存缓存优先机制:

// ========== Token 管理 ==========
// 获取 token(优先从内存读取)
getToken(): string | null

// 设置 token(同时写入内存和 localStorage)
setToken(token: string): void

// 移除 token(同时清除内存和 localStorage)
removeToken(): void

// ========== 用户信息管理 ==========
// 获取用户信息
getUserInfo<T>(): T | null

// 设置用户信息
setUserInfo(userInfo: any): void

// 移除用户信息
removeUserInfo(): void

// ========== 登录信息管理 ==========
// 获取登录信息(JeecgBoot 兼容)
getLoginInfo<T>(): 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<T>(key: string): T | null

// 移除动态 key 缓存
removeCacheByDynKey(key: string): void

性能说明

// 第一次读取:从 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. 跳转到登录页