
File name
Commit message
Commit date
File name
Commit message
Commit date
File name
Commit message
Commit date
import axios from 'axios';
import store from "../../views/pages/AppStore";
// JWT 토큰의 만료 시간 확인 함수
const isTokenExpired = () => {
try {
const token = store.state.authorization;
if (!token) return true;
// JWT 토큰 디코딩
const base64String = token.split('.')[1];
const base64 = base64String.replace(/-/g, '+').replace(/_/g, '/');
const jsonPayload = decodeURIComponent(atob(base64).split('').map(c => {
return '%' + ('00' + c.charCodeAt(0).toString(16)).slice(-2);
}).join(''));
const payload = JSON.parse(jsonPayload);
// exp는 토큰 만료 시간(Unix timestamp)
const expTime = payload.exp * 1000; // 밀리초 단위로 변환
const currentTime = new Date().getTime();
// 토큰 만료 5분 전부터는 미리 갱신
return currentTime > (expTime - 5 * 60 * 1000);
} catch (e) {
console.error("토큰 검증 오류:", e);
return true; // 오류 발생 시 만료된 것으로 간주
}
};
// 토큰 재발급 함수 (공통 함수로 분리)
const refreshToken = async () => {
try {
const res = await axios.post("/refresh/tknReissue.json", {}, {
headers: {
"Content-Type": "application/json; charset=UTF-8",
},
});
if (res.status === 200) {
// 새로 발급 받은 AccessToken 저장
store.commit('setAuthorization', res.headers.authorization);
// JWT 토큰 디코딩
const base64String = store.state.authorization.split('.')[1];
const base64 = base64String.replace(/-/g, '+').replace(/_/g, '/');
const jsonPayload = decodeURIComponent(atob(base64).split('').map(c => {
return '%' + ('00' + c.charCodeAt(0).toString(16)).slice(-2);
}).join(''));
const mbr = JSON.parse(jsonPayload);
store.commit("setUserNm", mbr.userNm); // 사용자 이름 저장
store.commit('setRoles', mbr.roles); // 사용자 역할 저장
return true;
}
throw new Error("토큰 재발급 요청 실패");
} catch (error) {
console.error("토큰 재발급 중 오류:", error);
throw error;
}
};
// 토큰 유효성 확인 및 필요시 갱신하는 함수
const ensureValidToken = async () => {
if (isTokenExpired()) {
try {
await refreshToken();
return true;
} catch (error) {
console.error("토큰 갱신 실패:", error);
throw error;
}
}
return true;
};
// Axios 클라이언트 생성 함수
const createClient = (contentType) => {
const client = axios.create({
headers: {
'Content-Type': contentType,
}
});
// 요청 인터셉터
client.interceptors.request.use(
async config => {
// 요청 전에 토큰 만료 확인 및 필요시 갱신
try {
await ensureValidToken();
const token = store.state.authorization;
if (token) {
config.headers.Authorization = token;
}
} catch (error) {
// 토큰 갱신 실패 시 로그인 페이지로 이동
if (!window.location.pathname.includes('/login')) {
const redirect = window.location.pathname + window.location.search;
sessionStorage.setItem("redirect", redirect);
alert('세션이 종료되었습니다.\n로그인을 새로 해주세요.');
store.commit("setStoreReset");
window.location = '/login.page';
}
throw error;
}
return config;
},
error => {
return Promise.reject(error);
}
);
// 응답 인터셉터
client.interceptors.response.use(
response => {
return response;
},
async error => {
const originalReq = error.config;
// 403 에러 처리
if (error.response && error.response.status === 403) {
alert('접근 권한이 없습니다.');
window.history.back();
return Promise.reject(error);
}
// 401 에러 처리 (토큰 만료)
if (error.response &&
error.response.status === 401 &&
error.response.data.message === '로그인 시간이 만료되었습니다.' &&
!originalReq._retry) {
originalReq._retry = true; // 재시도 플래그 설정
try {
// 토큰 재발급
await refreshToken();
// 새 토큰으로 헤더 업데이트
originalReq.headers.Authorization = store.state.authorization;
// multipart/form-data 요청 처리를 위한 특별 처리
if (originalReq.headers['Content-Type'] &&
originalReq.headers['Content-Type'].includes('multipart/form-data')) {
// 완전히 새로운 요청 생성
return axios({
...originalReq,
headers: {
...originalReq.headers,
Authorization: store.state.authorization
},
// FormData가 변경되지 않도록 원본 데이터 유지
transformRequest: [(data) => data]
});
}
// 일반 요청은 기존 client 사용하여 재시도
return client(originalReq);
} catch (refreshError) {
const redirect = window.location.pathname + window.location.search;
sessionStorage.setItem("redirect", redirect);
alert('세션이 종료되었습니다.\n로그인을 새로 해주세요.');
store.commit("setStoreReset");
window.location = '/login.page'; // 로그인 페이지로 리다이렉트
return Promise.reject(refreshError);
}
}
return Promise.reject(error);
}
);
return client;
};
// JSON 요청을 위한 apiClient
const apiClient = createClient('application/json; charset=UTF-8');
// 멀티파트 파일 업로드를 위한 fileClient
const fileClient = createClient('multipart/form-data');
export { apiClient, fileClient, ensureValidToken }; // 두 클라이언트와 토큰 유효성 확인 함수 내보냄