React로 로그인 구현하기( refreshToken, 로그아웃)

jaehan·2022년 8월 5일
0

React

목록 보기
9/33
post-thumbnail
post-custom-banner

refresh Token

우리 로그인 로직은 accessToken을 헤더에 담는 건데 새로고침을 하면 초기화 되기 때문에 다시 발급해줘야하는 상황이 발생한다.

그래서 사용한 것이 refreshToken이다.

또 다른 이유는 accessToken을 탈취 당했을때 다시 발급받기 위함과 유효기간을 연장시키기 위함이다.

accessToken은 탈취 당하면 재발급 하면 그만이지만 refreshToken을 탈취 당하면 보안에 크게 취약해 지기 때문에 서버에서 httpOnly : true 설정을 해줘서 클라이언트가 cookie를 사용하지 못하게 설정해 주었다.

💡 테스트 하다보니 response는 오는데 cookie는 안오는 상황이 생겨서 삽질을 좀 했는데 백과 프론트에서 withCredentials 설정을 true로 설정해주니까 해결되었다.

api 호출 ( post )

service/user.ts

export const mutateRefreshing = () => {
  const url = '/api/user-service/refresh';
  return axios.post<IResponseAuthToken>(url).then((res) => {
    return res.data;
  });
};

새로고침 할때마다 api 호출을 해서 refreshToken 도 재발급 받고 accessToken도 재발급 받아서 바로 헤더에 담아주었다.

hook (mutate)

hook/use-mutate-refreshing.ts

export const useMutateRefreshing = (
  mutateFunction: () => Promise<IResponseAuthToken>
) => {
  const navigate = useNavigate();
  const { mutate, data } = useMutation('refreshing', mutateFunction, {
    onSuccess: (data) => {
      axios.defaults.headers.common['Authorization'] =
        'Bearer ' + data.accessToken;
    },
    onError: () => {
      axios.defaults.headers.common['Authorization'] = '';
      navigate({
        pathname: '/signin',
      });
    },
  });

  return { mutate, data };
};

hook으로 빼준뒤에 성공시에 accessToken을 헤더에 바로 담아주었다.

실패했을때는 유효하지 않다는 뜻이기 때문에 헤더를 비워주고 바로 로그인 페이지로 가도록 useNavigate를 사용했다.

 useEffect(() => {
    refreshingHandler();
  }, []);

그리고 홈페이지 마다 useEffect로 새로고침할때마다 mutate하도록 추가해주었다.

로그아웃

원래는 클라이언트에서 쿠키를 삭제하는 방식으로 하려 했는데 httpOnly 를 true를 해놓으면 삭제도 안되어서 서버에서 쿠키를 삭제하는 방식을 사용했다.

그래서 간단하게 api 호출만 하면 되서 간단하게 구현할 수 있었다.

api 호출 ( get )

body가 필요 없어서 get으로 호출했다.

service/user.ts

export const mutateSignOut = () => {
  const url = `logout api`;
  return axios.get<IResponseAuth>(url).then((res) => {
    return res.data;
  });
};

hook ( mutate )

hook/use-mutate-refreshing.ts

export const useMutateSignOut = (
  mutateFunction: () => Promise<IResponseAuth>
) => {
  const navigate = useNavigate();
  const { mutate, data } = useMutation('signout', mutateFunction, {
    onSuccess: (data) => {
      axios.defaults.headers.common['Authorization'] = '';
      navigate({
        pathname: '/signin',
      });
    },
    onError: () => {},
  });

  return { mutate, data };
};

서버의 데이터를 조회만 하는게 아니라고 생각해서 useMutate를 사용했다.

로그아웃이기 때문에 헤더를 비워주고 로그인 페이지로 넘어가도록 설정했다.

post-custom-banner

0개의 댓글