This repository has been archived on 2026-08-12. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
Cyrene/frontend/web/src/store/authStore.ts
T
AskaEth a058b0ab8e fix: 第一轮修复 - 记忆管理/IoT操控/历史消息持久化/动作消息/链路优化/安全配置
- 修复记忆管理数据库连接不可用 (ai-core重编译+Unicode修复)
- 修复IoT子会话工具调用链路日志缺失
- 新增最终审查子会话(review_provider) 支持消息格式解析拆分
- 实现历史消息持久化(后端存储+前端分页加载)
- 前端新增动作消息(ActionMessage)类型和渲染
- 优化对话链路速度(非阻塞子会话+快速问候通道)
- JWT密钥环境变量化(无默认值启动panic)
- Token自动刷新机制(401拦截器+refresh接口)
- WebSocket指数退避重连(jitter+最大10次)
- localStorage清理一致性(cyrene_前缀+版本检查)
- IoT环境变量统一为IOT_SERVICE_URL
2026-05-21 23:10:07 +08:00

156 lines
4.3 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/**
* 认证状态管理 (Zustand Store)
* 用于跨组件共享登录/退出状态
*/
import { create } from 'zustand';
import { login as apiLogin, register as apiRegister, clearToken, isAuthenticated, getToken, getRefreshToken, setTokens } from '@/api/client';
/** localStorage key 前缀 */
const LS_VERSION_KEY = 'cyrene_store_version';
const CURRENT_VERSION = 1;
/** 所有 cyrene_ 前缀的 localStorage keyslogout 时全部清除 */
const CYRENE_KEYS = [
'token',
'refresh_token',
'user_id',
'user_nickname',
'cyrene_store_version',
];
function clearAllCyreneData(): void {
for (const key of CYRENE_KEYS) {
try {
localStorage.removeItem(key);
} catch { /* ignore */ }
}
}
interface AuthStore {
isLoggedIn: boolean;
userId: string | null;
token: string | null;
refreshToken: string | null;
loading: boolean;
login: (username: string, password: string) => Promise<{ success: boolean; error?: string }>;
register: (username: string, password: string, email: string, nickname: string, verifyCode: string) => Promise<{ success: boolean; error?: string }>;
logout: () => void;
setTokens: (accessToken: string, refreshToken?: string) => void;
clearAuth: () => void;
}
export const useAuthStore = create<AuthStore>((set) => ({
isLoggedIn: isAuthenticated(),
userId: localStorage.getItem('user_id'),
token: getToken(),
refreshToken: getRefreshToken(),
loading: false,
setTokens: (accessToken: string, refreshTokenValue?: string) => {
setTokens(accessToken, refreshTokenValue);
set({
isLoggedIn: true,
token: accessToken,
refreshToken: refreshTokenValue || null,
});
},
login: async (username: string, password: string) => {
set({ loading: true });
try {
const resp = await apiLogin(username, password);
if (resp.error) {
set({ loading: false });
return { success: false, error: resp.error };
}
set({
isLoggedIn: true,
userId: resp.data?.user_id || null,
token: resp.data?.token || null,
refreshToken: resp.data?.refresh_token || null,
loading: false,
});
return { success: true };
} catch (err) {
set({ loading: false });
return { success: false, error: err instanceof Error ? err.message : '登录失败' };
}
},
register: async (username: string, password: string, email: string, nickname: string, verifyCode: string) => {
set({ loading: true });
try {
const resp = await apiRegister(username, password, email, nickname, verifyCode);
if (resp.error) {
set({ loading: false });
return { success: false, error: resp.error };
}
// 保存昵称到 localStorage
if (resp.data?.nickname) {
localStorage.setItem('user_nickname', resp.data.nickname);
}
set({
isLoggedIn: true,
userId: resp.data?.user_id || null,
token: resp.data?.token || null,
refreshToken: resp.data?.refresh_token || null,
loading: false,
});
return { success: true };
} catch (err) {
set({ loading: false });
return { success: false, error: err instanceof Error ? err.message : '注册失败' };
}
},
logout: () => {
clearToken();
clearAllCyreneData();
set({
isLoggedIn: false,
userId: null,
token: null,
refreshToken: null,
loading: false,
});
},
clearAuth: () => {
clearToken();
clearAllCyreneData();
set({
isLoggedIn: false,
userId: null,
token: null,
refreshToken: null,
loading: false,
});
},
}));
/**
* 在应用启动时检查 localStorage 数据版本
* 如果版本不兼容,清除所有数据
*/
export function checkAndMigrateStore(): void {
try {
const storedVersion = localStorage.getItem(LS_VERSION_KEY);
if (storedVersion) {
const version = parseInt(storedVersion, 10);
if (version !== CURRENT_VERSION) {
console.log(`[store] localStorage 版本不兼容 (${version}${CURRENT_VERSION}),清除旧数据`);
clearAllCyreneData();
}
}
// 写入当前版本
localStorage.setItem(LS_VERSION_KEY, String(CURRENT_VERSION));
} catch {
// 忽略存储错误
}
}
/** 兼容旧代码的 Hook 导出 */
export function useAuth() {
return useAuthStore();
}