프로젝트 refreshToken이 수정되었다.
회원정보가 필요한 api 요청을 했을 때 401이 뜬다면
그에 맞추어서 refresh 하는 로직을 추가하려고 한다.
그전에 이 로직이 제대로 작동하는지, 시나리오는 어떻게 짜야할지 구성하기 위해서
로그인 시, 작동하는 디버깅 로직을 작성하였다.
로그인 화면에서 refresh가 필요한 경우는 없겠지만,
만료된 jwt 토큰을 연결해놓고 사용하기 편해서,
사용하였지만 완성한 후 돌이켜보니, 세션 스토리지에 넣어서 하는 방법이 더 좋아보인다.
기존의 코드도 안해치고, 편했을 거 같은데 다음에는 그런 방법을 사용해야겠다.
확실히 블로그로 정리하면서 다시 한번더 생각해보게 된다.
이제 본문으로 넘어가보자.
export default function Callback({}: Props) {
const setAccessToken = useSetRecoilState(accessTokenState);
const [lastPathState, setlastPathState] = useRecoilState(lastPath);
const router = useRouter();
const setUser = useSetRecoilState(userState);
useEffect(() => {
const accessToken = router.query.access_token as string;
if (accessToken) {
setAccessToken(accessToken as string); //토큰 저장
fetchUserData(accessToken as string)
.then((data) => {
setUser(data);
})
.catch((error) => {
console.error(error);
});
router.replace(lastPathState as string); //이전페이지로 이동
setlastPathState(null);
} else {
if (!lastPathState) router.replace("/"); //토큰이 없으면 메인으로 이동
}
}, [router]);
url에 받아오는 방식이었는데 input에 더미를 넣어서 하는 방식으로 수정하였다.
useEffect(() => {
console.log("렌더링");
if (accessToken) {
생략 }
else if (router.query.access_token) {
console.log("2");
setAccessToken(dummy); // 토큰 저장
} else if (!router.query.access_token && !lastPathState) {
console.log("3");
router.replace("/"); // 토큰이 없고 이전 경로가 없으면 메인으로 이동
}
}, [router.query.access_token]);
그러면 accessToken을 이용하여서 유저정보를 받아오는데
거기서 401이 발생하고, catch로 에러핸들링을 해줄 것이다.
명령형 프로그래밍 방식으로 작성하였다.
if (accessToken) {
fetchUserData(accessToken)
.then((data) => {
})
.catch((error) => {
if (error === 401) {
post_refresh()
.then((data: any) => {
setAccessToken(data.data);
console.log(data.data);
})
.catch((error) => {
console.error(error);
});
}
console.error(error);
});
401 -> catch ->
이후 post_refresh를 하고
accessToken을 다시 받아오면
setAccessToken으로 저장을 한다.
그러고 나서 다시 useEffect가 돌아서 유저정보를 요청하는 것이 목표였는데 작동하지 않았다.
현재 useEffect dependency에는 router.query.access_token, accessToken
2개가 들어있는데, useState가 아닌 recoil이어서 그런지
const [accessToken, setAccessToken] = useRecoilState(accessTokenState);
const [lastPathState, setlastPathState] = useRecoilState(lastPath);
const router = useRouter();
const setUser = useSetRecoilState(userState);
setAccessToken으로 업데이트를 했는데도 작동하지 않았다.
그래서 직접적으로 setAccessToken을 dependency에 추가하였다.
이 메서드가 사용된 후에 작동으로 useEffect가 돌아가게 되었고,
accessToken이 업데이트 되었을 때 자동으로 업데이트 되는 로직이 완성 되었다.
useEffect(() => {
if (accessToken) {
fetchUserData(accessToken)
.then((data) => {
setUser(data);
if (lastPathState) {
router.replace(lastPathState); // 이전 페이지로 이동
setlastPathState(null);
}
})
.catch((error) => {
if (error === 401) {
post_refresh()
.then((data: any) => {
setAccessToken(data.data);
console.log(data.data);
})
.catch((error) => {
console.error(error);
});
}
console.error(error);
});
} else if (router.query.access_token) {
setAccessToken(router.query.access_token as string); // 토큰 저장
} else if (!router.query.access_token && !lastPathState) {
router.replace("/"); // 토큰이 없고 이전 경로가 없으면 메인으로 이동
}
}, [router.query.access_token, accessToken, setAccessToken]);
이제 인증정보가 필요한 로직은 위와 같은 방식을 전부다 추가할 것이다.
하지만 아쉬운 점은 fetch로직을 함수로 작성하였는데 거기 안에서 처리하는 선언적 프로그래밍으로 처리하고 싶지만, 토큰을 다시 받아왔을 때 재요청을 하는 방법이 생각나지 않아 아쉽다.
그리고 브라우저의 디버깅 기능을 좀 더 잘사용해야겠다.
직접 값을 넣어주는 방식으로 사용해야 코드를 많이 안해치고 사용할 수 있어서
다음에는 그런 방법부터 먼저 고려해봐야겠다.
잘봤습니다.