// ============================================================ // useAuthState — 记住账号 / 记住密码 / 自动登录 状态管理 // // "记住密码":下次打开页面自动回填用户名 + 密码(Base64 编码) // "自动登录":登录成功时标记,AppProvider 启动时用 refresh_token 静默续期 // // 注意:密码 Base64 仅作基本混淆,非安全加密。 // 安全性由 refresh_token + access_token 的 JWT 双重机制保障。 // ============================================================ import { useState, useCallback } from 'react'; const STORAGE_KEY = 'ele-heixiu-auth'; interface StoredAuth { /** 上次登录的用户名(表单回填用) */ username: string; /** 密码的 Base64 编码(仅"记住密码"勾选时存储) */ passwordBase64?: string; /** 是否记住密码(勾选后表单自动回填用户名+密码) */ remember: boolean; /** 是否勾选了自动登录(AppProvider 据此决定启动时是否刷新 token) */ autoLogin: boolean; } function readAuth(): StoredAuth | null { try { const raw = localStorage.getItem(STORAGE_KEY); if (!raw) return null; return JSON.parse(raw) as StoredAuth; } catch { return null; } } function writeAuth(auth: StoredAuth): void { try { localStorage.setItem(STORAGE_KEY, JSON.stringify(auth)); } catch { /* 静默 */ } } // ---------- 工具函数(不依赖 React,AppProvider 可直接调用)---------- /** 读取自动登录标记 */ export function getAutoLoginFlag(): boolean { return readAuth()?.autoLogin || false; } /** 读取存储的密码(Base64 解码后返回明文,表单回填用) */ export function getStoredPassword(): string { const auth = readAuth(); if (!auth?.passwordBase64) return ''; try { return atob(auth.passwordBase64); } catch { return ''; } } /** 仅清除自动登录标记(保留用户名和密码,下次还能回填表单) */ export function clearAutoLoginFlag(): void { const auth = readAuth(); if (!auth) return; writeAuth({ ...auth, autoLogin: false }); } /** 清除所有保存的认证信息 */ export function clearSavedAuth(): void { try { localStorage.removeItem(STORAGE_KEY); } catch { /* 静默 */ } } // ---------- Hook ---------- export function useAuthState() { const saved = readAuth(); const [username, setUsername] = useState(saved?.username || ''); // 密码不存 state,直接从 localStorage 读取,避免 stale closure 问题 const [remember, setRemember] = useState(saved?.remember || false); const [autoLogin, setAutoLogin] = useState(saved?.autoLogin || false); const handleRememberChange = useCallback((checked: boolean) => { setRemember(checked); if (!checked) { setAutoLogin(false); clearSavedAuth(); } }, []); const handleAutoLoginChange = useCallback((checked: boolean) => { setAutoLogin(checked); }, []); /** * 登录成功后调用。 * 参数由调用方(LoginPage)直接从表单值传入,避免 useCallback 的 stale closure。 * * @param user - 用户名 * @param password - 明文密码(仅在"记住密码"勾选时存储,Base64 编码) * @param doRemember - 是否勾选"记住密码" * @param doAutoLogin - 是否勾选"自动登录" */ const saveAuth = useCallback( (user: string, password: string, doRemember: boolean, doAutoLogin: boolean) => { setUsername(user); if (doRemember || doAutoLogin) { const payload: StoredAuth = { username: user, remember: doRemember, autoLogin: doAutoLogin, }; // 仅在勾选"记住密码"时存储密码 if (doRemember && password) { try { payload.passwordBase64 = btoa(password); } catch { /* Base64 编码失败则放弃存储密码 */ } } writeAuth(payload); } }, [], ); return { username, remember, autoLogin, setUsername, handleRememberChange, handleAutoLoginChange, saveAuth, }; }