import { create } from "zustand";
import { persist } from "zustand/middleware";
import { setCookie, deleteCookie } from "@/lib/utils/cookie";
interface AuthState {
accessToken: string | null;
userId: number | null;
setAuth: (token: string, userId: number) => void;
clearAuth: () => void;
}
export const useAuthStore = create<AuthState>()(
persist(
(set) => ({
accessToken: null,
userId: null,
setAuth: (token, userId) =>
set(() => {
setCookie("accessToken", token); // ✅ 미들웨어가 읽을 수 있게 쿠키에 복제
return { accessToken: token, userId };
}),
clearAuth: () =>
set(() => {
deleteCookie("accessToken");
return { accessToken: null, userId: null };
}),
}),
{ name: "auth-storage" } // ✅ LocalStorage key
)
);
export function middleware(request: NextRequest) {
const token = request.cookies.get("accessToken")?.value;
const { pathname } = request.nextUrl;
const isAuthPage = pathname.startsWith("/login") || pathname.startsWith("/signup");
const isPublicPage = pathname === "/" || isAuthPage;
if (!token && !isPublicPage) {
return NextResponse.redirect(new URL("/login", request.url)); // 게스트 차단
}
if (token && isAuthPage) {
return NextResponse.redirect(new URL("/mydashboard", request.url)); // 인증자 차단
}
return NextResponse.next();
}
FOUC (Flash of Unstyled Content)란?
- 브라우저가 HTML을 먼저 그린 뒤, CSS나 JS가 늦게 로딩되면서 짧은 순간 '스타일 안 입혀진 날 것의 화면'이 번쩍 보이는 현상
import axios from "axios";
import { useAuthStore } from "@/lib/stores/auth";
export const api = axios.create({
baseURL: process.env.NEXT_PUBLIC_API_BASE_URL || "",
});
export const attachInterceptors = (router: { push: (s: string) => void }) => {
const reqId = api.interceptors.request.use((config) => {
const token = useAuthStore.getState().accessToken;
if (token) config.headers.Authorization = `Bearer ${token}`;
return config;
});
const resId = api.interceptors.response.use(
(res) => res,
(err) => {
if (err.response?.status === 401) {
useAuthStore.getState().clearAuth();
router.push("/login");
}
return Promise.reject(err);
}
);
return () => {
api.interceptors.request.eject(reqId);
api.interceptors.response.eject(resId);
};
};