기존 Filter + ArgumentResolver 구조를 Spring Security + JWT로 전환하기

E.NO·2026년 3월 4일

기존에 직접 구현했던 Servlet Filter(JwtFilter) + ArgumentResolver(AuthUserArgumentResolver) 기반 인증/인가 구조를 Spring Security 기반으로 전환했다.
토큰 기반 인증 방식(JWT)은 유지하면서, 권한 체크는 Spring Security의 인가 기능(authorizeHttpRequests, hasRole)을 사용하도록 변경했다.


기존 구조(변경 전)

1) JwtFilter(서블릿 필터)

  • 모든 요청에서 Authorization 헤더의 JWT를 꺼냄
  • 토큰 검증 후 Claims에서 값을 꺼내서 request.setAttribute(...)로 저장
    - userId, email, userRole

2) AuthUserArgumentResolver

  • 컨트롤러 파라미터에 @Auth AuthUser가 있으면
  • request.getAttribute(...)에서 위 값들을 가져와 AuthUser 객체로 만들어 주입

3) 권한 체크 방식

  • /admin/** 접근 여부를 필터에서 직접 if문으로 체크
  • 관리자 아닐 경우 403 반환

동작은 하지만,

  • 인증/인가 로직이 Security 표준 흐름(SecurityContext, Authentication)과 분리되어 있고
  • 역할(Role) 기반 인가를 Security에게 맡길 수 없어서 코드가 커질 가능성이 있었다.

목표(변경 후)

  • 인증: JWT 기반 유지
  • 사용자 정보 전달: request attribute 대신 SecurityContext에 Authentication 저장
  • 권한(Role) 체크: Spring Security의 인가 기능 사용
    - /admin/**는 ADMIN만 접근 가능

변경 후 구조(핵심 흐름)

1) JwtAuthenticationFilter(OncePerRequestFilter)로 교체

  • 기존 JwtFilter implements Filter 대신, Spring Security 필터 체인에 들어갈 수 있는 OncePerRequestFilter 기반 JwtAuthenticationFilter를 구현했다.

이 필터에서 하는 일은:
1. Authorization 헤더에서 JWT 추출
2. JwtUtil로 검증 + Claims 추출
3. Claims 기반으로 principal 생성 (AuthUser)
4. 권한을 GrantedAuthority로 변환 (ROLE_ADMIN / ROLE_USER)
5. SecurityContextHolder.getContext().setAuthentication(authentication) 저장

이제 컨트롤러/서비스는 “이 요청이 누구인지”를 SecurityContext에서 표준 방식으로 꺼낼 수 있다.


2) SecurityConfig에서 인가 규칙 선언

서블릿 필터에서 if문으로 처리하던 권한 체크를 아래처럼 Security 설정으로 옮겼다.

  • /auth/** : 로그인/회원가입 등 → permitAll()
  • /admin/** : 관리자만 → hasRole("ADMIN")
  • 그 외 → authenticated()

또한 JWT 기반이라 서버 세션은 사용하지 않으므로:

  • SessionCreationPolicy.STATELESS 적용
  • REST API라 CSRF는 비활성화(일반적인 JWT API 패턴)

이렇게 해서 “권한 정책”이 한곳(SecurityConfig)에 모이게 됐다.


3) ArgumentResolver 제거하고 Principal 기반으로 주입

기존에는 AuthUserArgumentResolver가 request attribute를 기반으로 AuthUser를 만들어줬다.
이제는 Authentication의 principal에 AuthUser가 들어있기 때문에 아래 방식으로 받을 수 있다.

  • @AuthenticationPrincipal AuthUser authUser

또는, 기존 형태(@Auth AuthUser)를 유지하고 싶으면 @Auth를 @AuthenticationPrincipal로 매핑하는 meta-annotation으로 바꾸면 된다.
결과적으로 WebConfig.addArgumentResolvers()와 AuthUserArgumentResolver는 더 이상 필요 없다.


적용 후 장점

  • 인가(권한 체크)가 표준화됨
    - 컨트롤러/필터에 if문으로 권한 분기할 필요가 없음
  • 인증 정보가 SecurityContext에 들어가서
    - @AuthenticationPrincipal, SecurityContextHolder 등 Spring Security 표준 기능을 그대로 활용 가능
  • 기능이 커질수록(Security, Method Security, @PreAuthorize 등) 확장하기가 훨씬 쉬워짐

오늘의 결론

JWT 인증은 유지하되, “사용자 정보 전달”과 “권한(Role) 기반 인가”를 Spring Security 표준 흐름으로 옮기면 코드가 단순해지고 정책이 한곳에 모여 유지보수가 쉬워진다.

0개의 댓글