흰 스타렉스에서 내가 내리지

Spring Security + JWT 흐름 간략하게 본문

Spring

Spring Security + JWT 흐름 간략하게

주씨. 2024. 1. 21. 23:48
728x90

 

# 큰 그림

클라이언트 → Apache Tomcat (:8080) → Spring Framework → 시큐리티 필터 → Dispatcher Servlet → Controller → Service → Repository → Persistence Context ←→ DB

 

* Dispatcher Servlet은 doPost, doDelete, doPut 등 서블릿의 생명주기를 가지고 있다. 주소를 파싱해서 컨트롤러를 찾아주는 역할을 한다. 

 

* @RestControlloerAdvice가 Dispatcher Servlet 단에서부터의 예외처리와 응답을 모두 책임진다.

# 작은 그림

#  1. 인증 필터

1. UsernamePasswordAuthenticationFilter (이하 JwtAuthenticationFilter) 에서 /login 의 경로에 대해 필터를 적용시킨다

2. JwtAuthenticationFilter.attemptAuthentication() 에서 username과 password 를 받아 dto 객체로 변환한다.

2-1. UsernamePasswordAuthenticationToken 타입의 인증 토큰을 생성한다. 이 인증토큰은 username과 password 를 인자로 받아 만들어진다. 

2-2 그 다음으로 AuthenticationManager.authenticate(authenticationToken) 를 호출을 하면, UserDetailsService (이하 LoginService) 의 loadUserByUsername() 메서드가 호출된다. 

2-3. LoginService.loadUserByUsername() 은 실제 DB로부터 저 username과 password를 가지고 있는 사용자가 있는지를 확인한다. 

2-4. DB를 확인하고, 로그인에 실패했을 경우에는 JwtAuthenticationFilter.unsuccessfulAuthentication() 이 호출되여 실패 응답을 보낸다. 

2-5. DB에 사용자가 존재하여 로그인에 성공하였을 경우엔 LoginService.loadByUsername() 이 LoginUser 객체를 생성하고 리턴한다. 

2-6. 여기까지 하면 아직 2-2번에서의 authenticate() 메서드에 위치해 있다. 이 메서드는 LoginUser 객체가 담긴 Authentication 객체를 리턴한다. 

2-7. 이 Authentication 객체는 세션영역의 일부인 SecurityContextHolder에 저장된다. 이 Authentication 객체는 응답을 마치면 바로 사라진다. SecurityConfig 에서 세션을 STATELESS 하게 설정했기 때문이다. 

2-8. JwtAuthenticationFilter.attemptAuthentication() 이 authentication을 리런하면, JwtAuthenticationFilter.successfulAuthentication() 을 호출한다. 

2-9. JwtAuthenticationFilter.successfulAuthentication() 은 Jwt 토큰을 생성하고, 이 토큰을 응답헤더에 받아서 리턴한다. 

 

 

# 2. 인가 필터

1. 클라이언트가 헤더에 JWT 를 담아 요청을 한다. 

2. JwtAuthorizedFilter.doFilterInternal() 메서드는 토큰을 검증하고, Authentication 객체를 강제로 만들고, SecurityContextHolder에 Authentication 객체를 저장한다. 

3. 이 때 만들어진 Authentication 속 LoginUser 객체는, 모든 정보가 포함되어있는 인증필터에서의 LoginUser와는 다르게, id와 role 만 들어가 있다. 

4. 이제 API가 들어오면, 세션을 확인하여 인증과 권한을 체크하고, 적절하게 처리를 해준다.