TIL - 20250810

juni·2025년 8월 10일

TIL

목록 보기
90/316

0810 Spring Security & JWT 인증 파이프라인 구축


✅ 1. 백엔드 인증 기반 구축 (Spring Security)

  • 회원가입/로그인 API 설계: Controller-Service-DTO 패턴을 기반으로 API의 기본 골격을 구현했습니다. 이를 통해 각 계층의 역할을 명확히 분리했습니다.
  • 비밀번호 암호화: 사용자의 비밀번호를 안전하게 보호하기 위해 Spring Security의 PasswordEncoder(BCryptPasswordEncoder 구현체)를 도입했습니다. 회원가입 시 비밀번호를 단방향 해시하여 DB에 저장하고, 로그인 시에는 입력된 비밀번호를 해시하여 저장된 값과 비교(matches())하는 방식으로 인증합니다.
  • 전역 예외 처리 (@RestControllerAdvice): GlobalExceptionHandler를 구현하여 애플리케이션 전역에서 발생하는 예외를 중앙에서 관리합니다. BusinessException (커스텀 예외)과 ErrorCode (Enum)를 활용해 비즈니스 로직 예외를 체계적으로 처리하고, 일관된 ErrorResponse를 클라이언트에게 반환합니다.
  • 표준 API 응답 (ApiResponse<T>): 모든 API 응답을 표준화된 형식으로 감싸(Wrapping) 클라이언트가 예측 가능한 데이터를 받을 수 있도록 설계했습니다.

✅ 2. JWT 기반 Stateless 인증 시스템 전환

  • 세션 기반 인증의 한계를 극복하고 Stateless(무상태) 인증을 구현하기 위해 JWT(JSON Web Token)를 도입했습니다. 서버는 토큰의 서명만 검증하면 되므로 확장성이 뛰어납니다.

➕ JWT 구현 핵심 요소

  1. jjwt 라이브러리 추가: build.gradle에 JWT 생성 및 검증을 위한 의존성을 추가했습니다.
  2. JwtProvider & JwtProperties:
    • JwtProvider: 토큰 생성, 정보 추출, 유효성 검증 로직을 캡슐화한 핵심 서비스 클래스입니다.
    • JwtProperties: application.yml에 정의된 비밀 키(Secret Key), 만료 시간 등의 설정을 객체로 관리합니다.
  3. 로그인 API 응답 수정: 로그인 성공 시, 서버는 사용자 정보를 담은 JWT를 생성하여 AuthResponse DTO에 담아 클라이언트에게 전달합니다. 클라이언트는 이 토큰을 저장해두고, 이후 API 요청 시마다 HTTP 헤더에 담아 보내 인증을 증명합니다.

✅ 3. 프론트엔드 모듈화 및 아키텍처 설계

  • JavaScript 코드의 유지보수성과 재사용성을 높이기 위해 ES6 모듈 시스템을 기반으로 프론트엔드 아키텍처를 설계했습니다.

➕ 주요 아키텍처 특징

  1. 동적 모듈 로딩 (Dynamic Import): App.js가 페이지 진입점 역할을 하며, 현재 URL을 분석해 import() 함수로 해당 페이지에 필요한 JS 모듈만 비동기적으로 로드합니다. 이를 통해 초기 로딩 속도를 최적화했습니다.
  2. 공통 모듈 분리:
    • api.js: 서버와의 모든 HTTP 통신(fetch)을 전담하는 모듈. API 호출 로직을 중앙에서 관리합니다.
    • util.js: 폼 검증, 메시지 표시 등 애플리케이션 전반에서 사용되는 유틸리티 함수를 모아놓은 모듈.
  3. 인증 상태 중앙 관리 (auth.js):
    • 인증과 관련된 모든 상태와 로직을 관리하는 싱글 소스 오브 트루스(Single Source of Truth) 역할을 합니다.
    • login(), logout(), isAuthenticated() 등의 메서드를 제공하여 로컬 스토리지의 토큰/사용자 정보를 안전하게 관리하고, 다른 모듈들이 쉽게 인증 상태를 확인하고 제어할 수 있도록 합니다.

✅ 4. 사용자 경험(UX) 고도화: 실시간 검증 및 동적 UI

  • 사용자가 더 편리하게 서비스를 이용할 수 있도록 프론트엔드 기능을 고도화했습니다.
  1. 실시간 유효성 검사:
    • 회원가입 폼의 각 필드(사용자명, 이메일, 비밀번호)에 대해 사용자가 입력하는 동안 실시간으로 유효성을 검사하고 피드백(안내 메시지, 아이콘)을 제공합니다.
    • 디바운스(Debounce) 기법을 적용하여, 키 입력이 멈춘 후에만 유효성 검사나 API 요청(중복 확인)이 실행되도록 하여 불필요한 연산을 줄이고 성능을 최적화했습니다.
  2. 서버 연동 중복 확인: 사용자명과 이메일은 debounce 처리된 입력 이벤트 후 백엔드 API(/check-username, /check-email)를 호출하여 실시간으로 중복 여부를 확인하고 결과를 UI에 즉시 반영합니다.
  3. 인증 상태 기반 동적 UI:
    • auth.js의 인증 상태를 기반으로 페이지의 UI를 동적으로 변경합니다.
    • 예시: 로그인 상태일 경우 헤더에 "로그아웃" 버튼을 표시하고, home.js에서는 사용자 환영 메시지를 보여줍니다. 비로그인 상태일 경우 "로그인" 버튼과 안내 문구를 표시합니다.

📌 요약

  • 백엔드에서는 Spring Security로 보안의 기틀을 잡고, 비밀번호 암호화와 체계적인 예외 처리, 표준 응답 구조를 구현했습니다.
  • 인증 방식은 세션에서 JWT 기반의 Stateless 인증으로 전환하여 확장성과 유연성을 확보했습니다.
  • 프론트엔드에서는 ES6 모듈동적 로딩으로 현대적인 아키텍처를 구축했으며, api.js, auth.js 등 공통 모듈을 통해 코드의 재사용성과 중앙 관리를 실현했습니다.
  • 사용자 경험 측면에서는 실시간 유효성 검사디바운싱, 동적 UI를 통해 직관적이고 반응성이 뛰어난 인터페이스를 완성했습니다.

0개의 댓글