61 lines
1.8 KiB
TypeScript
61 lines
1.8 KiB
TypeScript
|
|
import { create } from 'zustand';
|
|||
|
|
import { persist, createJSONStorage } from 'zustand/middleware';
|
|||
|
|
import type { AdminInfo } from '@/lib/types';
|
|||
|
|
|
|||
|
|
const TOKEN_COOKIE = process.env.NEXT_PUBLIC_TOKEN_KEY ?? 'admin_token';
|
|||
|
|
const TOKEN_LS_KEY = TOKEN_COOKIE; // 文档要求:JWT 仅前端 localStorage 存储
|
|||
|
|
|
|||
|
|
/** 把 token 同步到 Cookie,便于 Edge middleware 在 SSR 前拦截 */
|
|||
|
|
function syncCookie(token: string | null): void {
|
|||
|
|
if (typeof document === 'undefined') return;
|
|||
|
|
if (token) {
|
|||
|
|
const expires = new Date(Date.now() + 7 * 24 * 60 * 60 * 1000).toUTCString();
|
|||
|
|
document.cookie = `${TOKEN_COOKIE}=${encodeURIComponent(token)}; expires=${expires}; path=/; SameSite=Lax`;
|
|||
|
|
} else {
|
|||
|
|
document.cookie = `${TOKEN_COOKIE}=; expires=Thu, 01 Jan 1970 00:00:00 GMT; path=/;`;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/** 同步到 localStorage,axios 拦截器从这里取 */
|
|||
|
|
function syncLocalStorage(token: string | null): void {
|
|||
|
|
if (typeof window === 'undefined') return;
|
|||
|
|
if (token) {
|
|||
|
|
window.localStorage.setItem(TOKEN_LS_KEY, token);
|
|||
|
|
} else {
|
|||
|
|
window.localStorage.removeItem(TOKEN_LS_KEY);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
interface AdminState {
|
|||
|
|
token: string | null;
|
|||
|
|
admin: AdminInfo | null;
|
|||
|
|
setLogin: (token: string, admin: AdminInfo) => void;
|
|||
|
|
logout: () => void;
|
|||
|
|
hasAuth: () => boolean;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
export const useAdminStore = create<AdminState>()(
|
|||
|
|
persist(
|
|||
|
|
(set, get) => ({
|
|||
|
|
token: null,
|
|||
|
|
admin: null,
|
|||
|
|
setLogin: (token, admin) => {
|
|||
|
|
syncLocalStorage(token);
|
|||
|
|
syncCookie(token);
|
|||
|
|
set({ token, admin });
|
|||
|
|
},
|
|||
|
|
logout: () => {
|
|||
|
|
syncLocalStorage(null);
|
|||
|
|
syncCookie(null);
|
|||
|
|
set({ token: null, admin: null });
|
|||
|
|
},
|
|||
|
|
hasAuth: () => Boolean(get().token),
|
|||
|
|
}),
|
|||
|
|
{
|
|||
|
|
name: 'corp_admin_session',
|
|||
|
|
storage: createJSONStorage(() => localStorage),
|
|||
|
|
partialize: (s) => ({ token: s.token, admin: s.admin }),
|
|||
|
|
},
|
|||
|
|
),
|
|||
|
|
);
|