개발자

리액트 쿼리에서 사용자 인증관련 코드 질문있습니다.

2024년 03월 31일조회 195

아래 코드처럼 리액트쿼리로 사용자 인증 코드를 구현했습니다. ( 외국 개발자분 코드 분석해서 거의 복붙하고 조금 수정 ) 간단히, api요청을 해서 유저 정보를 받아 로컬스토리지에 저장해서 사용하는 코드입니다. 이 훅을 프라이빗 라우터 및 로그인 버튼 or 사용자 이름 표시 UI 에 사용중인데요 쿼리 캐시 때문에 계속 요청을안하고 그값만 계속 사용중인데 이 사용자의 토큰 유효기간이 지났는데도 계속 그 값만 사용중입니다. 이 분기처리를 어떻게 해줘야할지를 모르겠습니다. 처음엔 refetchOnMount: false,를 true로 바꿔주고 토큰 유효값이 지나면 에러를 뱉어주는거를 보고 흡족해했으나 네트워크탭을 살펴보니 새로고침, 페이지 인아웃 할때마다 계속 요청을하고있어서 다시 고민에빠졌습니다. 어떤식으로 해줘야 할까요?.. 가장 생각나는건 statleTime 값을 토큰 유효기간 값만큼 설정해주면 될까 인데.. 이렇게해줘도되나요?

1import { useQuery, useQueryClient } from '@tanstack/react-query';
2import instance from 'api/instance';
3import { IUserInfo } from 'interface/auth';
4import { useEffect } from 'react';
5import { userKey } from 'react-query-key/auth.keys';
6import * as userLocalStorage from './user.localstorage';
7
8const fetchUserInfo = async (user: any) => {
9  const token = localStorage.getItem(userLocalStorage.USER_LOCAL_STORAGE_KEY);
10  const res: any = await instance.get('/api/auth', {
11    headers: {
12      Authorization: `Bearer ${JSON.parse(token as any).token}`,
13    },
14  });
15
16  return res.data;
17};
18
19interface IUseUser {
20  user: IUserInfo | null;
21}
22
23export function useUser(): IUseUser {
24  const queryClient = useQueryClient();
25
26  const { error, data: user } = useQuery({
27    queryKey: [userKey.user],
28    queryFn: async () => await fetchUserInfo(userLocalStorage.getUser()),
29    initialData: userLocalStorage.getUser,
30    refetchOnMount: false,
31    refetchOnWindowFocus: false,
32    refetchOnReconnect: false,
33  });
34
35  useEffect(() => {
36    if (!user || error) {
37      queryClient.setQueryData([userKey.user], null);
38      userLocalStorage.removeUser();
39    } else userLocalStorage.saveUser(user);
40  }, [user, error, queryClient]);
41
42  return {
43    user: user ?? null,
44  };
45}
이 질문이 도움이 되었나요?
'추천해요' 버튼을 누르면 좋은 질문이 더 많은 사람에게 노출될 수 있어요. '보충이 필요해요' 버튼을 누르면 질문자에게 질문 내용 보충을 요청하는 알림이 가요.

답변 2

김태형님의 프로필 사진

토큰 사용할 때 (정보 조회나 작업) 토큰 만료 반환할 때 재발급 요청하는 식으로 하면 되지 않나요??

개발새발님의 프로필 사진

개발새발

작성자

없다고 비전공2024년 04월 01일

저도 첨에 그렇게 생각했는데.. 주로 PrivateRoute에서 저 코드를 훅으로 사용합니다. 근데 이렇게되면 토큰이 만료된 상태인데도 여전히 사용자는 정상작동하는것처럼 보였습니다. 401에러를 뱉어야되는데 그러지도 않고.. 그래서 그냥 옵션으로 토큰 유효기간 만큼의 시간을 주는식으로했습니다. staleTime: 1000 * 60 * 10, // 10분 refetchInterval: 1000 * 60 * 10, // 10분 리프레쉬인터벌이 작동하면 토큰도 유효기간이 끝나니까 401을뱉고, 리프레시 토큰 api가 작동해서 자동으로 토큰유효기간을 연장해주는 식으로했습니다.. 이게 맞는건진 모르겠는데 일단 이렇게했습니다..ㅜ

ccat님의 프로필 사진

LocalStroge에 user정보를 담지 않고 오로지 accessToken 과 refreshToken을 발급 받게 해야합니다. 그리고 각 페이지 요청이 들어갈 때 accessToken 및 refreshToken을 백엔드에 넘겨서 백엔드에서 token값을 확인 하고 정보를 넘기는 식으로 해야 맞습니다! 이렇게 한다면 굳이 프론트에서 처리를 하지 않아도 됩니당

지금 가입하면 모든 질문의 답변을 볼 수 있어요!

현직자들의 명쾌한 답변을 얻을 수 있어요.

또는

이미 회원이신가요?

AI 답변
커리어리 AI 봇 프로필 이미지

커리어리 AI 봇

GPT가 달아주는 답변입니다.

2024년 03월 31일

리액트 쿼리의 `staleTime` 설정을 토큰의 유효 시간과 같게 설정하는 것은 올바른 해결책일 수 있습니다. 이렇게 하면 토큰이 만료되는 동시에 데이터가 "stale" 상태가 되고, 다음 개인 정보 요청에서 자동으로 새로운 데이터를 가져옵니다. ```javascript export function useUser(): IUseUser { const queryClient = useQueryClient(); const tokenExpiry = userLocalStorage.getUser()?.tokenExpiry; ... const { error, data: user } = useQuery({ queryKey: [userKey.user], queryFn: async () => await fetchUserInfo(userLocalStorage.getUser()), initialData: userLocalStorage.getUser, refetchOnMount: false, refetchOnWindowFocus: false, refetchOnReconnect: false, staleTime: tokenExpiry // Add this line }); ... } ``` 그러나 이 방법은 토큰 만료 시간을 정확하게 알고 있어야 합니다. 또한 서버에서 토큰이 만료되었다는 응답을 받으면 로컬 스토리지에서 토큰을 제거하고 사용자를 로그아웃 처리해야합니다. 또는 아니면 any로 선언된 res 부분에 타입을 지정해서 response가 오류일 경우 에러 핸들링하는 로직도 필요할 것 같습니다. 이 경우에는 사용자의 토큰이 만료되면 서버에서 401 Unauthorized 응답을 전송할 것입니다(만약 그렇게 구성되어 있다면). 이 에러를 캐치하면 로그인 페이지로 리디렉션나 다른 오류 처리를 할 수 있습니다. ```javascript const fetchUserInfo = async (user: any) => { const token = localStorage.getItem(userLocalStorage.USER_LOCAL_STORAGE_KEY); try { const res: ResponseTypeHere = await instance.get('/api/auth', { // replace 'ResponseTypeHere' with actual type. headers: { Authorization: `Bearer ${JSON.parse(token as any).token}`, }, }); return res.data; } catch (err) { if (err.response.status === 401) { // the token has expired or is invalid. Handle this error here. userLocalStorage.removeUser(); } } }; ``` 추가적으로, 항상 최신 상태를 유지해야하는 데이터의 경우 staleTime을 지정하지 않거나 짧은 시간을 설정하는 것이 좋습니다. 한편, 자주 바뀌지 않는 데이터의 경우 staleTime 값을 길게 설정해 네트워크 요청을 줄일 수 있습니다. 따라서 토큰 유효값에 맞춰서 staleTime을 설정하는 것은 올바른 접근 방식일 수 있습니다.

목록으로

지금 가입하면 모든 질문의 답변을 볼 수 있어요!