Files
sam-react-prod/claudedocs/[IMPL-2025-11-07] middleware-issue-resolution.md
byeongcheolryu 2307b1f2c0 [docs]: 프로젝트 문서 추가
세부 항목:
- 인증 및 미들웨어 구현 가이드
- 품목 관리 마이그레이션 가이드
- API 분석 및 요구사항 문서
- 대시보드 통합 완료 문서
- 브라우저 호환성 및 쿠키 처리 가이드
- Next.js 15 마이그레이션 참고 문서

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-13 21:17:43 +09:00

4.6 KiB

Middleware 인증 문제 해결 보고서

📅 작성일: 2025-11-07

🔍 문제 증상

로그인하지 않은 상태에서 /dashboard에 접근 시, 인증 체크가 작동하지 않고 대시보드에 바로 접근되는 문제가 발생했습니다.

증상 상세

  • 로그인/로그아웃 기능 정상 작동
  • 쿠키(user_token) 저장/삭제 정상
  • Middleware에서 보호된 라우트 접근 차단 실패
  • Middleware console.log가 터미널에 전혀 출력되지 않음

🐛 발견된 문제들

1. Next.js 15 + next-intl 호환성 문제

위치: next.config.ts

원인:

  • Next.js 15에서 next-intl v4를 사용할 때 turbopack 설정이 필수
  • 이 설정이 없으면 middleware가 제대로 컴파일되지 않음

해결:

// next.config.ts
const nextConfig: NextConfig = {
  turbopack: {}, // ✅ 추가
};

2. 복잡한 Matcher 정규식

위치: src/middleware.ts - config.matcher

원인:

  • 너무 복잡한 regex 패턴으로 라우트 매칭 실패
  • 중복된 matcher 패턴 (정규식 + 명시적 경로)

기존 코드:

matcher: [
  '/((?!_next/static|_next/image|favicon.ico|.*\\.(?:svg|png|jpg|jpeg|gif|webp|ico)$).*)',
  '/dashboard/:path*',
  '/login',
  '/register',
]

해결:

matcher: [
  '/((?!api|_next/static|_next/image|favicon.ico|.*\\..*|robots\\.txt).*)',
]

3. isPublicRoute 함수 로직 버그 (핵심 문제)

위치: src/middleware.ts - isPublicRoute() 함수

원인:

// 문제 코드
function isPublicRoute(pathname: string): boolean {
  return AUTH_CONFIG.publicRoutes.some(route =>
    pathname === route || pathname.startsWith(route)
  );
}

버그 시나리오:

  1. AUTH_CONFIG.publicRoutes'/' 포함
  2. /dashboard.startsWith('/') → true 반환
  3. 모든 경로가 public route로 잘못 판단됨
  4. 인증 체크가 스킵되어 보호된 라우트 접근 가능

해결:

function isPublicRoute(pathname: string): boolean {
  return AUTH_CONFIG.publicRoutes.some(route => {
    // '/' 는 정확히 일치해야만 public
    if (route === '/') {
      return pathname === '/';
    }
    // 다른 라우트는 시작 일치 허용
    return pathname === route || pathname.startsWith(route + '/');
  });
}

수정 후 동작:

  • / → public
  • /dashboard → protected
  • /about → public
  • /about/team → public

해결 결과

적용된 수정 사항

  1. next.config.tsturbopack: {} 추가
  2. Middleware matcher 단순화
  3. isPublicRoute() 함수 로직 수정
  4. 디버깅 로그 제거 (클린 코드)

검증 결과

# 로그아웃 상태에서 /dashboard 접근 시:
[Auth Required] Redirecting to /login from /dashboard
→ 자동으로 /login 페이지로 리다이렉트 ✅

# 로그인 상태에서 /dashboard 접근 시:
[Authenticated] Mode: bearer, Path: /dashboard
→ 정상 접근 ✅

📝 교훈

1. Middleware 디버깅

  • 브라우저 콘솔이 아닌 서버 터미널에서 로그 확인
  • console.log는 서버 사이드에서 실행되므로 터미널 출력

2. 문자열 매칭 주의

  • startsWith('/') 같은 패턴은 모든 경로와 매칭됨
  • Root path(/)는 항상 정확한 일치(===) 사용

3. Next.js 버전별 설정

  • Next.js 15 + next-intl 사용 시 turbopack 설정 필수
  • 공식 문서 및 마이그레이션 가이드 확인 필요

🔗 관련 파일

수정된 파일

  • next.config.ts - turbopack 설정 추가
  • src/middleware.ts - isPublicRoute 로직 수정, matcher 단순화

관련 설정 파일

  • src/lib/api/auth/auth-config.ts - 라우트 설정
  • src/lib/api/auth/sanctum-client.ts - 인증 로직
  • src/lib/api/auth/token-storage.ts - 토큰 관리

🎯 현재 인증 플로우

로그인

  1. 사용자가 /login에서 인증 정보 입력
  2. PHP API(/api/v1/login)로 요청 (API Key 포함)
  3. Bearer Token 발급 (user_token)
  4. localStorage 저장 + Cookie 동기화
  5. /dashboard로 리다이렉트

보호된 라우트 접근

  1. Middleware에서 요청 가로채기
  2. Cookie에서 user_token 확인
  3. 토큰 있음 → 통과
  4. 토큰 없음 → /login으로 리다이렉트

로그아웃

  1. PHP API(/api/v1/logout) 호출
  2. localStorage 및 Cookie 정리
  3. /login으로 리다이렉트

📚 참고 자료

  • Next.js 15 Middleware 공식 문서
  • next-intl v4 마이그레이션 가이드
  • claudedocs/research_nextjs15_middleware_authentication_2025-11-07.md