jskim-node #402
|
|
@ -2,7 +2,6 @@
|
|||
// Phase 2-1B: 핵심 인증 API 구현
|
||||
|
||||
import { Router } from "express";
|
||||
import { checkAuthStatus } from "../middleware/authMiddleware";
|
||||
import { AuthController } from "../controllers/authController";
|
||||
|
||||
const router = Router();
|
||||
|
|
@ -12,7 +11,7 @@ const router = Router();
|
|||
* 인증 상태 확인 API
|
||||
* 기존 Java ApiLoginController.checkAuthStatus() 포팅
|
||||
*/
|
||||
router.get("/status", checkAuthStatus);
|
||||
router.get("/status", AuthController.checkAuthStatus);
|
||||
|
||||
/**
|
||||
* POST /api/auth/login
|
||||
|
|
|
|||
|
|
@ -161,13 +161,14 @@ export const useAuth = () => {
|
|||
setLoading(true);
|
||||
|
||||
const token = TokenManager.getToken();
|
||||
if (!token || TokenManager.isTokenExpired(token)) {
|
||||
AuthLogger.log("AUTH_CHECK_FAIL", `refreshUserData: 토큰 ${!token ? "없음" : "만료됨"}`);
|
||||
if (!token) {
|
||||
AuthLogger.log("AUTH_CHECK_FAIL", "refreshUserData: 토큰 없음");
|
||||
setUser(null);
|
||||
setAuthStatus({ isLoggedIn: false, isAdmin: false });
|
||||
setLoading(false);
|
||||
return;
|
||||
}
|
||||
// 만료된 토큰이라도 apiClient 요청 인터셉터가 자동 갱신하므로 여기서 차단하지 않음
|
||||
|
||||
AuthLogger.log("AUTH_CHECK_START", "refreshUserData: API로 인증 상태 확인 시작");
|
||||
|
||||
|
|
@ -177,6 +178,10 @@ export const useAuth = () => {
|
|||
});
|
||||
|
||||
try {
|
||||
// /auth/me 성공 = 인증 확인 완료. /auth/status는 보조 정보(isAdmin)만 참조
|
||||
// 두 API를 Promise.all로 호출 시, 토큰 만료 타이밍에 따라
|
||||
// /auth/me는 401→갱신→성공, /auth/status는 200 isAuthenticated:false를 반환하는
|
||||
// 레이스 컨디션이 발생할 수 있으므로, isLoggedIn 판단은 /auth/me 성공 여부로 결정
|
||||
const [userInfo, authStatusData] = await Promise.all([fetchCurrentUser(), checkAuthStatus()]);
|
||||
|
||||
if (userInfo) {
|
||||
|
|
@ -184,19 +189,12 @@ export const useAuth = () => {
|
|||
|
||||
const isAdminFromUser = userInfo.userId === "plm_admin" || userInfo.userType === "ADMIN";
|
||||
const finalAuthStatus = {
|
||||
isLoggedIn: authStatusData.isLoggedIn,
|
||||
isLoggedIn: true,
|
||||
isAdmin: authStatusData.isAdmin || isAdminFromUser,
|
||||
};
|
||||
|
||||
setAuthStatus(finalAuthStatus);
|
||||
AuthLogger.log("AUTH_CHECK_SUCCESS", `사용자: ${userInfo.userId}, 인증: ${finalAuthStatus.isLoggedIn}`);
|
||||
|
||||
if (!finalAuthStatus.isLoggedIn) {
|
||||
AuthLogger.log("AUTH_CHECK_FAIL", "API 응답에서 비인증 상태 반환 → 토큰 제거");
|
||||
TokenManager.removeToken();
|
||||
setUser(null);
|
||||
setAuthStatus({ isLoggedIn: false, isAdmin: false });
|
||||
}
|
||||
} else {
|
||||
AuthLogger.log("AUTH_CHECK_FAIL", "userInfo 조회 실패 → 토큰 기반 임시 인증 유지 시도");
|
||||
try {
|
||||
|
|
@ -412,18 +410,19 @@ export const useAuth = () => {
|
|||
|
||||
const token = TokenManager.getToken();
|
||||
|
||||
if (token && !TokenManager.isTokenExpired(token)) {
|
||||
AuthLogger.log("AUTH_CHECK_START", `초기 인증 확인: 유효한 토큰 존재 (경로: ${window.location.pathname})`);
|
||||
if (token) {
|
||||
// 유효/만료 모두 refreshUserData로 처리
|
||||
// apiClient 요청 인터셉터가 만료 토큰을 자동 갱신하므로 여기서 삭제하지 않음
|
||||
const isExpired = TokenManager.isTokenExpired(token);
|
||||
AuthLogger.log(
|
||||
"AUTH_CHECK_START",
|
||||
`초기 인증 확인: 토큰 ${isExpired ? "만료됨 → 갱신 시도" : "유효"} (경로: ${window.location.pathname})`,
|
||||
);
|
||||
setAuthStatus({
|
||||
isLoggedIn: true,
|
||||
isAdmin: false,
|
||||
});
|
||||
refreshUserData();
|
||||
} else if (token && TokenManager.isTokenExpired(token)) {
|
||||
AuthLogger.log("TOKEN_EXPIRED_DETECTED", `초기 확인 시 만료된 토큰 발견 → 정리 (경로: ${window.location.pathname})`);
|
||||
TokenManager.removeToken();
|
||||
setAuthStatus({ isLoggedIn: false, isAdmin: false });
|
||||
setLoading(false);
|
||||
} else {
|
||||
AuthLogger.log("AUTH_CHECK_FAIL", `초기 확인: 토큰 없음 (경로: ${window.location.pathname})`);
|
||||
setAuthStatus({ isLoggedIn: false, isAdmin: false });
|
||||
|
|
|
|||
|
|
@ -329,6 +329,11 @@ apiClient.interceptors.request.use(
|
|||
const newToken = await refreshToken();
|
||||
if (newToken) {
|
||||
config.headers.Authorization = `Bearer ${newToken}`;
|
||||
} else {
|
||||
// 갱신 실패 시 인증 없는 요청을 보내면 TOKEN_MISSING 401 → 즉시 redirectToLogin 연쇄 장애
|
||||
// 요청 자체를 차단하여 호출부의 try/catch에서 처리하도록 함
|
||||
authLog("TOKEN_REFRESH_FAIL", `요청 인터셉터에서 갱신 실패 → 요청 차단 (${config.url})`);
|
||||
return Promise.reject(new Error("TOKEN_REFRESH_FAILED"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue