Skip to content

세션 정보 참조 가이드

dictionary-app은 로그인 세션 사용자 정보를 useSessionStore(zustand, localStorage 영속화)에 두고, 어느 컴포넌트에서든 이 훅으로 읽는다. 스토어 자체의 전체 정의는 스토어 가이드의 useSessionStore 항목 참고 — 이 문서는 “참조해서 쓰는” 소비 패턴에 집중한다.

  1. 사용자 이름 표시 + 게스트 배지 — sessionUser가 없으면(비로그인) 아무 것도 렌더링하지 않는다.
    layout/header/Header.tsx
    export const Header = () => {
    const {sessionUser} = useSessionStore()
    return (
    <Flex as="header">
    {sessionUser && (
    <Flex align="center" gap={3} ml="auto">
    {sessionUser.guestYn === 'Y' && (
    <Badge colorPalette="orange" variant="subtle" size="sm">
    게스트
    </Badge>
    )}
    <Text fontSize="sm" color="fg">
    {sessionUser.userNm}님
    </Text>
    </Flex>
    )}
    </Flex>
    )
    }
  2. 게스트 계정 여부로 메뉴 항목을 필터링한다.
    components/organisms/menu/Menu.tsx
    export const Menu = ({items, depth = 0}: MenuProps) => {
    const {sessionUser} = useSessionStore()
    const isGuest = sessionUser?.guestYn === 'Y'
    const visibleItems = isGuest
    ? items.filter((item) => item.menuName !== GUEST_HIDDEN_MENU_NAME)
    : items
    return <>{/* visibleItems 렌더링 */}</>
    }
  3. adminYn/guestYn처럼 값이 'Y'/'N' 문자열이라는 점에 주의한다 — boolean이 아니라 백엔드 SessionUser DTO의 원본 타입 그대로다.

서버 세션 재확인 — useSessionFindQuery

Section titled “서버 세션 재확인 — useSessionFindQuery”
  1. localStorage에 남은 로그인 상태만 믿지 않고, 주기적으로 GET /v1/auth/find-session을 호출해 서버 세션이 실제로 살아있는지 확인한다. 401이 아닌 에러(네트워크 순단 등)는 “로그인되지 않음”으로 취급하지 않도록 구분해서 반환한다.
    hooks/queries/useSessionFindQuery.ts
    const SESSION_CHECK_INTERVAL_MS = 1000 * 60 * 5
    export const useSessionFindQuery = () => {
    const {findSession} = useAuthApi()
    const {
    data: sessionUser,
    isLoading: isSessionChecking,
    error: sessionError,
    } = useQuery({
    queryKey: ['auth', 'session'],
    queryFn: ({signal}) => findSession(signal),
    retry: false,
    refetchInterval: SESSION_CHECK_INTERVAL_MS,
    })
    const isSessionExpired = isUnauthorizedError(sessionError)
    return {sessionUser, isSessionChecking, isSessionExpired}
    }
  2. 이 훅은 인증 가드(RequireAuth)가 소비한다 — 확인에 성공하면 useSessionStore를 최신화하고, 401이면 비운다. 전체 코드는 스토어 가이드의 useSessionStore 사용 예 참고.

응답마다 만료 시각 갱신 — useAxiosInterceptor

Section titled “응답마다 만료 시각 갱신 — useAxiosInterceptor”
  1. 백엔드는 모든 API 응답 봉투에 expiresAt(슬라이딩 세션의 실제 만료 시각)을 함께 내려준다 — 어느 API를 호출했는지와 무관하게 매 응답마다 이 값으로 세션 스토어를 최신화해야 실제 서버 값과 어긋나지 않는다.
    hooks/useAxiosInterceptor.ts
    instance.interceptors.response.use(
    (response) => {
    const expiresAt = (response.data as ResponseDto<unknown> | undefined)?.expiresAt
    if (expiresAt !== undefined) {
    setExpiresAt(expiresAt)
    }
    return response
    },
    (error) => {
    if (isUnauthorizedError(error)) {
    removeSessionUser()
    queryClient.clear()
    navigate('/login', {replace: true})
    }
    return Promise.reject(error)
    },
    )
  2. 401 응답을 받으면(진짜 세션 만료) 세션 스토어를 비우고 react-query 캐시를 초기화한 뒤 /login으로 이동한다 — Header의 수동 로그아웃 처리와 동일한 절차다.