로그인 되어있을 시 /main 으로 이동
This commit is contained in:
parent
bc8587f688
commit
03039ab743
|
|
@ -63,13 +63,19 @@ const TokenManager = {
|
||||||
|
|
||||||
setToken: (token: string): void => {
|
setToken: (token: string): void => {
|
||||||
if (typeof window !== "undefined") {
|
if (typeof window !== "undefined") {
|
||||||
|
// localStorage에 저장
|
||||||
localStorage.setItem("authToken", token);
|
localStorage.setItem("authToken", token);
|
||||||
|
// 쿠키에도 저장 (미들웨어에서 사용)
|
||||||
|
document.cookie = `authToken=${token}; path=/; max-age=86400; SameSite=Lax`;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
removeToken: (): void => {
|
removeToken: (): void => {
|
||||||
if (typeof window !== "undefined") {
|
if (typeof window !== "undefined") {
|
||||||
|
// localStorage에서 제거
|
||||||
localStorage.removeItem("authToken");
|
localStorage.removeItem("authToken");
|
||||||
|
// 쿠키에서도 제거
|
||||||
|
document.cookie = "authToken=; path=/; max-age=0; SameSite=Lax";
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -61,11 +61,15 @@ export const useLogin = () => {
|
||||||
* API 호출 공통 함수
|
* API 호출 공통 함수
|
||||||
*/
|
*/
|
||||||
const apiCall = useCallback(async (endpoint: string, options: RequestInit = {}): Promise<LoginResponse> => {
|
const apiCall = useCallback(async (endpoint: string, options: RequestInit = {}): Promise<LoginResponse> => {
|
||||||
|
// 로컬 스토리지에서 토큰 가져오기
|
||||||
|
const token = localStorage.getItem("authToken");
|
||||||
|
|
||||||
const response = await fetch(`${API_BASE_URL}${endpoint}`, {
|
const response = await fetch(`${API_BASE_URL}${endpoint}`, {
|
||||||
credentials: "include",
|
credentials: "include",
|
||||||
headers: {
|
headers: {
|
||||||
"Content-Type": "application/json",
|
"Content-Type": "application/json",
|
||||||
Accept: "application/json",
|
Accept: "application/json",
|
||||||
|
...(token && { Authorization: `Bearer ${token}` }),
|
||||||
...options.headers,
|
...options.headers,
|
||||||
},
|
},
|
||||||
...options,
|
...options,
|
||||||
|
|
@ -90,16 +94,19 @@ export const useLogin = () => {
|
||||||
// 토큰이 있으면 API 호출로 유효성 확인
|
// 토큰이 있으면 API 호출로 유효성 확인
|
||||||
const result = await apiCall(AUTH_CONFIG.ENDPOINTS.STATUS);
|
const result = await apiCall(AUTH_CONFIG.ENDPOINTS.STATUS);
|
||||||
|
|
||||||
if (result.success && result.data?.isLoggedIn) {
|
// 백엔드가 isAuthenticated 필드를 반환함
|
||||||
|
if (result.success && result.data?.isAuthenticated) {
|
||||||
// 이미 로그인된 경우 메인으로 리다이렉트
|
// 이미 로그인된 경우 메인으로 리다이렉트
|
||||||
router.push(AUTH_CONFIG.ROUTES.MAIN);
|
router.push(AUTH_CONFIG.ROUTES.MAIN);
|
||||||
} else {
|
} else {
|
||||||
// 토큰이 유효하지 않으면 제거
|
// 토큰이 유효하지 않으면 제거
|
||||||
localStorage.removeItem("authToken");
|
localStorage.removeItem("authToken");
|
||||||
|
document.cookie = "authToken=; path=/; max-age=0; SameSite=Lax";
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
// 에러가 발생하면 토큰 제거
|
// 에러가 발생하면 토큰 제거
|
||||||
localStorage.removeItem("authToken");
|
localStorage.removeItem("authToken");
|
||||||
|
document.cookie = "authToken=; path=/; max-age=0; SameSite=Lax";
|
||||||
console.debug("기존 인증 체크 중 오류 (정상):", error);
|
console.debug("기존 인증 체크 중 오류 (정상):", error);
|
||||||
}
|
}
|
||||||
}, [apiCall, router]);
|
}, [apiCall, router]);
|
||||||
|
|
@ -128,9 +135,12 @@ export const useLogin = () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
if (result.success && result.data?.token) {
|
if (result.success && result.data?.token) {
|
||||||
// JWT 토큰 저장
|
// JWT 토큰 저장 (localStorage와 쿠키 모두에 저장)
|
||||||
localStorage.setItem("authToken", result.data.token);
|
localStorage.setItem("authToken", result.data.token);
|
||||||
|
|
||||||
|
// 쿠키에도 저장 (미들웨어에서 사용)
|
||||||
|
document.cookie = `authToken=${result.data.token}; path=/; max-age=86400; SameSite=Lax`;
|
||||||
|
|
||||||
// 로그인 성공
|
// 로그인 성공
|
||||||
router.push(AUTH_CONFIG.ROUTES.MAIN);
|
router.push(AUTH_CONFIG.ROUTES.MAIN);
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -148,13 +158,10 @@ export const useLogin = () => {
|
||||||
[formData, validateForm, apiCall, router],
|
[formData, validateForm, apiCall, router],
|
||||||
);
|
);
|
||||||
|
|
||||||
// 컴포넌트 마운트 시 기존 인증 상태 확인 (한 번만 실행)
|
// 컴포넌트 마운트 시 기존 인증 상태 확인
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
// 로그인 페이지에서만 실행
|
checkExistingAuth();
|
||||||
if (window.location.pathname === "/login") {
|
}, [checkExistingAuth]);
|
||||||
checkExistingAuth();
|
|
||||||
}
|
|
||||||
}, []); // 의존성 배열을 비워서 한 번만 실행
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
// 상태
|
// 상태
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,55 @@
|
||||||
|
import { NextResponse } from "next/server";
|
||||||
|
import type { NextRequest } from "next/server";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Next.js 미들웨어
|
||||||
|
* 페이지 렌더링 전에 실행되어 인증 상태를 확인하고 리다이렉트 처리
|
||||||
|
*/
|
||||||
|
export function middleware(request: NextRequest) {
|
||||||
|
const { pathname } = request.nextUrl;
|
||||||
|
|
||||||
|
// 인증 토큰 확인
|
||||||
|
const token = request.cookies.get("authToken")?.value || request.headers.get("authorization")?.replace("Bearer ", "");
|
||||||
|
|
||||||
|
// /login 페이지 접근 시
|
||||||
|
if (pathname === "/login") {
|
||||||
|
// 토큰이 있으면 메인 페이지로 리다이렉트
|
||||||
|
if (token) {
|
||||||
|
const url = request.nextUrl.clone();
|
||||||
|
url.pathname = "/main";
|
||||||
|
return NextResponse.redirect(url);
|
||||||
|
}
|
||||||
|
// 토큰이 없으면 로그인 페이지 표시
|
||||||
|
return NextResponse.next();
|
||||||
|
}
|
||||||
|
|
||||||
|
// 인증이 필요한 페이지들
|
||||||
|
const protectedPaths = ["/main", "/admin", "/dashboard", "/settings"];
|
||||||
|
const isProtectedPath = protectedPaths.some((path) => pathname.startsWith(path));
|
||||||
|
|
||||||
|
if (isProtectedPath && !token) {
|
||||||
|
// 인증되지 않은 사용자는 로그인 페이지로 리다이렉트
|
||||||
|
const url = request.nextUrl.clone();
|
||||||
|
url.pathname = "/login";
|
||||||
|
return NextResponse.redirect(url);
|
||||||
|
}
|
||||||
|
|
||||||
|
return NextResponse.next();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 미들웨어가 실행될 경로 설정
|
||||||
|
*/
|
||||||
|
export const config = {
|
||||||
|
matcher: [
|
||||||
|
/*
|
||||||
|
* 다음 경로를 제외한 모든 요청에 대해 실행:
|
||||||
|
* - api (API routes)
|
||||||
|
* - _next/static (static files)
|
||||||
|
* - _next/image (image optimization files)
|
||||||
|
* - favicon.ico (favicon file)
|
||||||
|
* - public 폴더의 파일들
|
||||||
|
*/
|
||||||
|
"/((?!api|_next/static|_next/image|favicon.ico|.*\\.png$|.*\\.jpg$|.*\\.jpeg$|.*\\.svg$).*)",
|
||||||
|
],
|
||||||
|
};
|
||||||
Loading…
Reference in New Issue