
현재 문제: 접근 권한이 필요한 페이지에서 새로고침 시 로그인 페이지로 이동한 후 인증 처리가 다시 이루어짐.
원인: 새로고침 시 스토어의 데이터가 초기화되고, 쿠키에 저장된 토큰은 여전히 유효하기 때문에 다시 유효성을 검사하는 비동기 요청이 발생함. 이때, role 정보가 없는 상태이므로 로그인 페이지로 이동하게 됨.
명칭: AuthProvider의 명칭이 다소 애매함 ⇒ AuthGuard가 더 적합함. '인증으로 보호하는' 느낌을 더 잘 전달함.
Provider: 컴포넌트 트리의 하위 컴포넌트들에게 데이터를 제공하는 역할을 하는 컴포넌트를 의미함.
useFetchSignIn에서 로그인이 성공한 경우, 사용자를 '/' 경로로 보낸다.AuthProvider가 동작하여 보호된 페이지가 있는지 판단한다.useAuth의 내부 로직에서 userId가 변동되면, 토큰이 존재하는 경우 유효성을 검증하기 위해 프로필 정보를 요청한다.AuthProvider가 동작하여 useAuth의 인증을 통과했는지 확인한 후 페이지 인가 처리를 한다.보호된 페이지에서 인가된 상태에서 새로고침 시, 스토어의 데이터가 초기화되어 로그인 페이지로 이동하게 된다. 그 후, 비동기 처리를 통해 뒤늦게 유효성 검사 결과가 처리되어, 로그인 페이지 상태에서 다시 인증이 완료된다.
먼저 위와 같은 시나리오를 적용하기 위해 useFetchSigin의 페이지 전환을 제거하고 로그인 페이지 내부에 토큰이 유효한경우 사용자의 정보를 요청하는 작업을 진행했다. 또 이전 페이지에 돌려보내주기 위해 유저 정보 스토어에 history 라는 상태도 추가하여 작업을 진행 해보았다.
const useAuthRedirect = () => {
const router = useRouter();
const { accessToken } = getCookies();
const { history } = useAuthStore();
useEffect(() => {
if (accessToken) {
router.replace(history ?? '/');
}
}, [accessToken, history, router]);
};
export default useAuthRedirect;
로그인 페이지 접근 했을 시 토큰이 존재하면 history로 돌려보내줬다.
하지만 문제는 로그인페이지를 거치기 때문에 로그인 페이지를 거쳐 토큰이 존재하는 것을 확인하고 history 로 돌려보내는 절차가 너무 눈에 보인다는 것이다.

URL을 통해 로그인 페이지로 접근하는 테스트를 수행한 결과, 화면에서 보이는 것처럼 로그인 페이지를 거친 후 다시 원래 페이지로 돌아오는 것을 확인할 수 있었다.
이전에 학습한 미들웨어의 문제는 prefetch가 캐싱된다는 점이다. 이로 인해 <Link />를 통해 페이지에 재접근할 경우, 캐싱된 결과 때문에 이전과 동일한 문제가 발생할 수 있다.
하지만 로그인 페이지의 경우, 사용자가 로그인을 완료한 이후에는 로그아웃을 하거나 URL을 통해서만 새로 접근할 수 있기 때문에 동일한 <Link />를 다시 클릭할 일이 없다.
따라서 로그인 페이지에 접근하면 미들웨어가 이를 감지하여 토큰이 없는 경우 정상적으로 로그인 페이지를 보여주고, 토큰이 존재하는 경우에는 이전 페이지로 되돌려 보내기로 했다.
import { NextRequest, NextResponse } from 'next/server';
import { TOKEN_KEYS } from '@/src/shared/const';
export function middleware(req: NextRequest) {
const token = req.cookies.get(TOKEN_KEYS.ACCESS_TOKEN);
if (token) {
// Referer 헤더에서 이전 페이지 URL 가져오기
const referer = req.headers.get('referer') || req.nextUrl.origin;
return NextResponse.redirect(referer);
}
return NextResponse.next();
}
// 특정 경로에만 미들웨어 적용
export const config = {
matcher: ['/login'],
};
미들웨어는 로그인 시에만 동작하도록 설정하였으며, 리퍼러(Referer)를 체크하여 토큰이 존재하는 경우 이전 페이지로 다시 돌려보내도록 하였다. 반면, 토큰이 존재하지 않는 경우에는 정상적인 로그인 페이지로 안내하여 처리하였다.
.
아직도 이것이 최선의 방법인지는 잘 모르겠다. 어떻게 하면 더 나은 방법에 도달할 수 있을까 고민하며, 처음에는 HOC를 사용하다가 미들웨어로 변경했지만, prefetch 캐싱 문제로 실패를 경험했다. 다시 HOC로 돌아가려 했지만, FSD 아키텍처와 queryProvider 문제를 고려하면 HOC가 좋은 선택은 아니라는 결론에 이르렀다. 그래서 현재로서는 최선의 방법을 선택했다고 생각했다.
그러나 로그인 페이지를 거치는 좋지 않은 구조를 해결하기 위해, 이번에는 prefetch 캐싱을 고려하여 미들웨어로 다시 접근해 보았다. 이 방법이 맞는 선택인지는 아직 확신할 수 없다. 이런 순간마다 함께 의견을 나눌 동료가 있었다면 정말 좋았을 것 같다. 더 나은 결과를 만들고 싶지만, 스스로 생각하는 데 한계가 느껴진다....