[jwt] refresh token으로 memory에 저장되어있던 사라진 access token 재발급 받기
로그인 후 새로고침을 하면
memory, 즉 redux에 저장되어있던
access token과 user가 사라져버린다.
그래서 구현하려고 했던 것은
1. user와 access token이 없는데 refresh token이 남아 있는 경우
cookie에 저장되어있던 refresh token을 가지고 access token을 재발급 받은 후,
2. 재발급 받은 access token으로 다시 데이터를 가져와서
3. 해당 데이터를 가지고 화면을 재 렌더링 해준다.
문제 상황 :
refresh token으로 access token을 재발급 받고
데이터를 다시 가져왔으나,
해당 데이터로 화면이 재렌더링 되지 않는 현상이 있었다.
문제 이유 :
조건문이 잘못되었다는 것을 깨달았다.
해결방법은 코드를 실행할때마다 어떤 상태에서 코드가 실행되었는지
코드 실행순서를 자세하게 살펴보았다.
로그인할때 부터 순서를 간단히 요약하자면 아래와 같다:
1. 로그인을 한다 .
2. 서버에서 access 와 refresh token을 발급받는다.
3. 가져온 access token은 redux에 저장하고, decode하여 유저정보를 redux user상태에 저장하며,
refresh token은 cookie에 저장한다.
4. useEffect가 변경된 user를 감지하여 저장되어있는 엑세스 토큰으로 데이터를 가져온다.
5. 가져온 데이터를 redux에 저장한다.
6. 해당 데이터의 상태를 구독하고 있던 컴포넌트에서 변경을 감지하고, 컴포넌트를 리렌더링하여
화면에 변경된 데이터를 볼 수 있게 된다.
그런데 여기서 새로고침을 한다면,
1. redux에 저장되어있던 user와 access token은 사라지고,
2. cookie에 저장되어있던 refresh token은 그대로 남아있다.
3. 그러므로 user가 없으므로 아래 코드의 조건은 false가 되어 실행되지 않고
4. else문이 실행되어 logout을 함과 동시에 login화면으로 넘어가버리게 된다.
문제의 코드 :
//미션 내용 가져오기
useEffect(() => {
if (user && refreshToken) {
dispatch(getToken(refreshToken));
dispatch(fetchMissionData(authToken));
} else {
//로그아웃을 누르거나 refreshToken이 만료되면 logout후 login화면으로
dispatch(authActions.logout());
navigate("/login");
}
}, [dispatch, navigate, authToken, refreshToken, user]);
변경된 코드 :
Mission.jsx 중 일부
//미션 내용 가져오기
useEffect(() => {
if (user || tokenIsChanged) {
//user가 있거나 token이 변경된 경우 미션목록을 다시 가져오기
console.log(
"토큰이 변경되거나 유저가 설정되어 미션목록을 다시 가져옵니다" +
"user : " +
user +
"tokenIsChanged : " +
tokenIsChanged
);
console.log(user);
dispatch(fetchMissionData(authToken));
}
//authToken이 없고 refreshToken이 있는경우 토큰 재발급
if (!user && refreshToken) {
console.log("엑세스토큰이 없습니다. 엑세스토큰을 재발급합니다.");
dispatch(getToken(refreshToken));
}
//refreshToken이 없을때 로그아웃.
if (!refreshToken) {
//로그아웃을 누르거나 refreshToken이 만료되면 logout후 login화면으로
console.log("리프레시 토큰이 만료되었으므로 로그아웃합니다.");
dispatch(authActions.logout());
navigate("/login");
}
}, [dispatch, navigate, authToken, refreshToken, user, tokenIsChanged]);
1. 먼저 tokenIsChanged state를 redux에 추가하여 기본값은 false로 해준다.
2. 그리고 useEffect에 새로고침 시 user가 사라지고 refresh token만 존재할 때의 조건문에
getToken이란 thunk를 실행하여 남아있는 refresh token으로 access token을 재발급 해준다.
3. 재발급 받은 access token은 다시 redux에 저장하여 주고 그것과 함께
tokenIsChanged를 true로 해준다.
4. 그러면 위 코드의 3째줄의 조건문이 참이되어 변경된 access token으로 mission Data 를 가져오는 thunk를 실행한다.
5. 다시 가져온 데이터를 redux에 저장하여 준다.
6. 저장된 데이터 상태를 구독하고 있던 Mission.jsx 컴포넌트가 변경을 감지하여 리렌더링된다.
7. 변경된 데이터로 화면이 보이게 된다.
느낀점 :
처음에 코드의 진행순서를 정확히 파악하지 않은 것이 에러의 원인이었다.
내가 생각하던 대로 코드가 작동하려면
진행순서를 파악한뒤 그에 맞는 조건문을 조정하면 순차적으로 진행될 것을 알게 되었다.