해결된 질문
작성
·
52
0
안녕하세요.
access Token 정보 만료 후에 서버에서 보내는 메시지가 401 메시지로 옵니다.
그래서인지 jwtUtil.js 파일에서 처리를 못하는 문제가 있는 것이 맞을까요?
responseFail 을 아래와 같이 수정하는게 맞는지 무엇을 놓치고 있는 것인지 모르겠습니다.
http://localhost:3000/todo/list 를 10분 이상 경과후 실행했을 때 에러 메시지를 출력했었습니다.
import axios from "axios";
import {getCookie, setCookie} from "./cookieUtil";
import {API_SERVER_HOST} from "../api/hostApi";
const jwtAxios = axios.create()
const refreshJWT = async (accessToken, refreshToken) => {
const host = API_SERVER_HOST
const header = {headers: {"Authorization": `Bearer ${accessToken}`}}
const res = await axios.get(`${host}/api/member/refresh?refreshToken=${refreshToken}`, header)
console.log("----------------------")
console.log(res.data)
return res.data
}
//before request
const beforeReq = (config) => {
console.log("before request.............")
const memberInfo = getCookie("member")
if (!memberInfo) {
console.log("Member NOT FOUND")
return Promise.reject(
{
response:
{
data:
{error: "REQUIRE_LOGIN"}
}
}
)
}
const {accessToken} = memberInfo
// Authorization 헤더 처리
config.headers.Authorization = `Bearer ${accessToken}`
return config
}
//fail request
const requestFail = (err) => {
console.log("request error............")
return Promise.reject(err)
}
//before return response
const beforeRes = async (res) => {
console.log("before return response...........")
console.log(res)
//'ERROR_ACCESS_TOKEN'
const data = res.data
if (data && data.error === 'ERROR_ACCESS_TOKEN') {
const memberCookieValue = getCookie("member")
const result = await refreshJWT(memberCookieValue.accessToken, memberCookieValue.refreshToken)
console.log("refreshJWT RESULT", result)
memberCookieValue.accessToken = result.accessToken
memberCookieValue.refreshToken = result.refreshToken
setCookie("member", JSON.stringify(memberCookieValue), 1)
//원래의 호출
const originalRequest = res.config
originalRequest.headers.Authorization = `Bearer ${result.accessToken}`
return await axios(originalRequest)
}
return res
}
//fail response
const responseFail = async (err) => {
console.log("response fail error.............")
console.log(err)
const originalRequest = err.config;
// 토큰 만료로 인한 401 응답이라면 → refresh 시도
if (
err.response &&
err.response.status === 401 &&
!originalRequest._retry // 무한 루프 방지
) {
originalRequest._retry = true;
const memberCookieValue = getCookie("member");
try {
const result = await refreshJWT(
memberCookieValue.accessToken,
memberCookieValue.refreshToken
);
// 토큰 저장
memberCookieValue.accessToken = result.accessToken;
memberCookieValue.refreshToken = result.refreshToken;
setCookie("member", JSON.stringify(memberCookieValue), 1);
// 원래 요청 재시도
originalRequest.headers.Authorization = `Bearer ${result.accessToken}`;
return await axios(originalRequest);
} catch (refreshError) {
console.error("Refresh 실패, 로그아웃 처리 필요");
// 로그아웃 로직 연결 가능
localStorage.removeItem("token");
return Promise.reject(refreshError);
}
}
return Promise.reject(err);
}
jwtAxios.interceptors.request.use(beforeReq, requestFail)
jwtAxios.interceptors.response.use(beforeRes, responseFail)
export default jwtAxios
답변 3
0
JWTCheckFilter에서 401에러를 만들어서 보내시는 부분이 있네요
본인이 작성하신 코드
} catch (Exception e) {
log.error("JWT Check Failed: {}", e.getMessage());
// 4. 인증 실패 응답 세팅
response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
response.setContentType("application/json");
String msg = new Gson().toJson(Map.of("error", "ERROR_ACCESS_TOKEN"));
try (PrintWriter writer = response.getWriter()) {
writer.println(msg);
}
// 5. 인증 정보 초기화 (중요)
SecurityContextHolder.clearContext();
}
--------------------------------
예제 코드
}catch(Exception e){
log.error("JWT Check Error..............");
log.error(e.getMessage());
Gson gson = new Gson();
String msg = gson.toJson(Map.of("error", "ERROR_ACCESS_TOKEN"));
response.setContentType("application/json");
PrintWriter printWriter = response.getWriter();
printWriter.println(msg);
printWriter.close();
}
0
음.. 좀 이상하네요..
서버의 JWTCheckFilter의 경우 accessToken을 검증한 후에 문제가 발생하면 catch로 빠지게 됩니다.
그런데 catch에서는 보내는 메세지는 그냥 200 번 상태 코드이고 'ERROR_ACCESS_TOKEN'으로 나가는게 맞습니다.
그러니 리액트 코드에서는 responseFail 에 걸리는게 아니라 beforeRes에 걸려야만 합니다.
제가 소스 코드를 실행해서 확인해 봐야 정확히 말씀드릴 수 있을 듯 합니다.
cookie_00@naver.com으로 소스 코드를 실행할 수 있는 링크나 방법등을 알려주시면 실행해서 원인을 좀 더 살펴보겠습니다.
0
안녕하세요, 인프런 AI 인턴입니다. Link님.
Access Token이 만료된 후 401 오류가 발생하며, 이로 인해 jwtUtil.js에서 적절히 처리되지 않는 상황을 겪고 계시는군요. jwtAxios 인터셉터 설정에 대해 함께 살펴보고 개선할 수 있는 부분을 안내해 드리겠습니다.
기존 코드에서는 401 상태 코드가 반환될 때, 새로운 Access Token을 획득하기 위해 Refresh Token을 사용하여 토큰 갱신을 시도합니다. 이를 위해 responseFail과 beforeRes에 관련 로직이 포함되어 있습니다.
Refresh Token 호출 검사: refreshJWT
함수에서 사용되는 URL 및 헤더 설정 등이 올바른지 한번 더 확인해 보세요. 특히 헤더의 Authorization 설정이 정확한지 여부가 중요합니다.
무한 루프 방지: originalRequest._retry
플래그를 사용하여 무한 루프를 예방하고 있으므로, 이 부분이 잘 작동하고 있는지 확인하세요.
로그아웃 로직 강화: Refresh Token이 손상되거나 실패할 경우 사용자를 로그아웃 시키는 로직을 준비해두는 것이 좋습니다. 이는 사용자 경험을 안정적으로 유지하는 데 도움을 줄 수 있습니다.
추가적인 사용자 안내: Refresh Token 갱신 과정이나 오류 발생 시 사용자에게 명확한 안내(알림 메시지 등)를 제공하여 혼란을 줄일 수 있습니다.
관련하여 참고할 수 있는 질문과 답변 URL을 추천해 드립니다. 이들 게시물에서는 토큰 만료 관련된 유사한 문제와 해결책을 논의하고 있습니다.
저는 질문자님의 이해를 돕고자 지식공유자님의 기존 답변을 참고하여 유사한 답변 링크를 추천해드리고 있습니다. 현재 베타 기능으로 답변이 만족스럽지 않을 수 있는 점 양해 부탁드립니다. 🙏 추가적으로 궁금한 점이 있으시면, 이어서 질문해 주세요. 곧 지식공유자께서 답변해 주실 것입니다.
감사합니다.
제가 Spring Boot 은 이제 배우는 초보라서 아는게 턱없이 부족합니다.
잘 동작하는 거 확인했습니다.