216 lines
5.3 KiB
JavaScript
216 lines
5.3 KiB
JavaScript
|
|
import { useCache, CACHE_KEY, deleteTokenCache } from '../hooks/web/useCache'
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* Token 统一管理模块(Monorepo 全局工具)
|
|||
|
|
*
|
|||
|
|
* 这是项目中唯一的 token 管理入口,所有 token 操作都应该通过此模块进行。
|
|||
|
|
*
|
|||
|
|
* Token 存储优先级(读取顺序):
|
|||
|
|
* 1. 手动输入的 dev token (sessionStorage)
|
|||
|
|
* 2. 正式登录的 token (wsCache/localStorage)
|
|||
|
|
* 3. 环境变量 VITE_DEV_TOKEN
|
|||
|
|
*
|
|||
|
|
* Token 存储位置:
|
|||
|
|
* - ACCESS_TOKEN/access_token: 访问令牌(wsCache/localStorage)
|
|||
|
|
* - REFRESH_TOKEN/refresh_token: 刷新令牌(wsCache/localStorage)
|
|||
|
|
* - DEV_MANUAL_TOKEN: 开发手动输入的token(sessionStorage)
|
|||
|
|
*/
|
|||
|
|
|
|||
|
|
// ==================== 常量定义 ====================
|
|||
|
|
const DEV_MANUAL_TOKEN_KEY = 'DEV_MANUAL_TOKEN'
|
|||
|
|
|
|||
|
|
// Token 键名变体(支持大小写不同)
|
|||
|
|
const TOKEN_KEYS = {
|
|||
|
|
ACCESS: [CACHE_KEY.ACCESS_TOKEN, 'access_token'],
|
|||
|
|
REFRESH: [CACHE_KEY.REFRESH_TOKEN, 'refresh_token']
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// ==================== 缓存实例管理 ====================
|
|||
|
|
let wsCache = null
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* 获取 wsCache 实例(延迟初始化,避免模块加载时出错)
|
|||
|
|
* @returns {Object} wsCache 实例
|
|||
|
|
*/
|
|||
|
|
function getCache() {
|
|||
|
|
if (!wsCache) {
|
|||
|
|
try {
|
|||
|
|
wsCache = useCache().wsCache
|
|||
|
|
} catch (e) {
|
|||
|
|
console.warn('初始化 wsCache 失败:', e)
|
|||
|
|
// 返回一个安全的空对象,避免后续调用出错
|
|||
|
|
wsCache = {
|
|||
|
|
get: () => null,
|
|||
|
|
set: () => {},
|
|||
|
|
delete: () => {}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
return wsCache
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* 获取完整的 Authorization Header 值
|
|||
|
|
* @returns {string} Bearer token 或空字符串
|
|||
|
|
*/
|
|||
|
|
export function getAuthHeader() {
|
|||
|
|
const token = getToken()
|
|||
|
|
return token ? `Bearer ${token}` : ''
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* 获取 token
|
|||
|
|
* @returns {string} token 字符串
|
|||
|
|
*/
|
|||
|
|
export function getToken() {
|
|||
|
|
// 1. 优先使用手动输入的 dev token
|
|||
|
|
const manualToken = sessionStorage.getItem(DEV_MANUAL_TOKEN_KEY)
|
|||
|
|
if (manualToken) {
|
|||
|
|
return manualToken
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 2. 使用正式登录的 token(从 wsCache 读取)
|
|||
|
|
try {
|
|||
|
|
const cache = getCache()
|
|||
|
|
// 尝试所有可能的键名变体
|
|||
|
|
for (const key of TOKEN_KEYS.ACCESS) {
|
|||
|
|
const accessToken = cache.get(key)
|
|||
|
|
if (accessToken) {
|
|||
|
|
return accessToken
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
} catch (e) {
|
|||
|
|
console.warn('获取 wsCache 失败:', e)
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 3. 兜底:环境变量中的 token
|
|||
|
|
const envToken = import.meta?.env?.VITE_DEV_TOKEN
|
|||
|
|
if (envToken) {
|
|||
|
|
return envToken
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
return ''
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* 设置手动输入的 dev token
|
|||
|
|
* @param {string} token
|
|||
|
|
*/
|
|||
|
|
export function setDevToken(token) {
|
|||
|
|
if (token) {
|
|||
|
|
sessionStorage.setItem(DEV_MANUAL_TOKEN_KEY, token)
|
|||
|
|
} else {
|
|||
|
|
sessionStorage.removeItem(DEV_MANUAL_TOKEN_KEY)
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* 获取手动输入的 dev token(用于显示)
|
|||
|
|
* @returns {string}
|
|||
|
|
*/
|
|||
|
|
export function getDevToken() {
|
|||
|
|
return sessionStorage.getItem(DEV_MANUAL_TOKEN_KEY) || ''
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* 设置访问令牌和刷新令牌
|
|||
|
|
* @param {Object} tokens - token 对象
|
|||
|
|
* @param {string} tokens.accessToken - 访问令牌
|
|||
|
|
* @param {string} tokens.refreshToken - 刷新令牌
|
|||
|
|
*/
|
|||
|
|
export function setToken(tokens) {
|
|||
|
|
if (!tokens || (!tokens.accessToken && !tokens.refreshToken)) {
|
|||
|
|
console.warn('setToken: token 参数无效', tokens)
|
|||
|
|
return
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
try {
|
|||
|
|
const cache = getCache()
|
|||
|
|
if (tokens.accessToken) {
|
|||
|
|
cache.set(CACHE_KEY.ACCESS_TOKEN, tokens.accessToken)
|
|||
|
|
}
|
|||
|
|
if (tokens.refreshToken) {
|
|||
|
|
cache.set(CACHE_KEY.REFRESH_TOKEN, tokens.refreshToken)
|
|||
|
|
}
|
|||
|
|
} catch (e) {
|
|||
|
|
console.error('设置 token 失败:', e)
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* 获取刷新令牌
|
|||
|
|
* @returns {string|null} 刷新令牌或 null
|
|||
|
|
*/
|
|||
|
|
export function getRefreshToken() {
|
|||
|
|
try {
|
|||
|
|
const cache = getCache()
|
|||
|
|
// 尝试所有可能的键名变体
|
|||
|
|
for (const key of TOKEN_KEYS.REFRESH) {
|
|||
|
|
const token = cache.get(key)
|
|||
|
|
if (token) {
|
|||
|
|
return token
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
} catch (e) {
|
|||
|
|
console.warn('获取 refresh token 失败:', e)
|
|||
|
|
}
|
|||
|
|
return null
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* 清除所有 token
|
|||
|
|
* 清空所有可能的 token 存储位置,确保完全清除
|
|||
|
|
*/
|
|||
|
|
export function clearAllTokens() {
|
|||
|
|
try {
|
|||
|
|
// 1. 清空 sessionStorage 中的 dev token
|
|||
|
|
sessionStorage.removeItem(DEV_MANUAL_TOKEN_KEY)
|
|||
|
|
} catch (e) {
|
|||
|
|
console.warn('清除 sessionStorage token 失败:', e)
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
try {
|
|||
|
|
// 2. 清空 wsCache (localStorage) 中的所有可能的 token 键名
|
|||
|
|
// 使用统一的 deleteTokenCache 函数,保持与 useCache 的一致性
|
|||
|
|
deleteTokenCache()
|
|||
|
|
} catch (e) {
|
|||
|
|
console.warn('清除 wsCache token 失败:', e)
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
try {
|
|||
|
|
// 3. 清空 localStorage 中可能的 token(兜底处理)
|
|||
|
|
// 注意:wsCache 默认使用 localStorage,但为了确保清除,也直接操作 localStorage
|
|||
|
|
const localStorageKeys = [
|
|||
|
|
...TOKEN_KEYS.ACCESS,
|
|||
|
|
...TOKEN_KEYS.REFRESH,
|
|||
|
|
DEV_MANUAL_TOKEN_KEY
|
|||
|
|
]
|
|||
|
|
localStorageKeys.forEach(key => {
|
|||
|
|
try {
|
|||
|
|
localStorage.removeItem(key)
|
|||
|
|
} catch (e) {
|
|||
|
|
// 忽略单个键删除失败
|
|||
|
|
}
|
|||
|
|
})
|
|||
|
|
} catch (e) {
|
|||
|
|
console.warn('清除 localStorage token 失败:', e)
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* 删除 token(别名,兼容旧代码)
|
|||
|
|
* @deprecated 使用 clearAllTokens() 代替
|
|||
|
|
*/
|
|||
|
|
export function removeToken() {
|
|||
|
|
clearAllTokens()
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* 获取访问令牌(别名,兼容旧代码)
|
|||
|
|
* @returns {string} token 字符串
|
|||
|
|
*/
|
|||
|
|
export function getAccessToken() {
|
|||
|
|
return getToken()
|
|||
|
|
}
|
|||
|
|
|