Spring Security에서 JWT를 발급 받는 방법은 크게 두 가지로 볼 수 있습니다.
첫째는 구글 검색을 통해서도 흔히 볼 수 있는 Controller를 이용해서 아이디/패스워드 로그인 후, JWT를 발급 받는 방식이고, 두 번째는 Spring Security에서 지원하는 Security Filter를 확장하는 방법입니다.
Controller를 이용하는 것이 안좋은 방법이라고 보기는 힘들지만 그래도 Spring Security라는 보안 프레임워크를 사용하는 개발자 입장에서는 Controller까지 request가 전달되기 전에 Security Filter 레벨에서 인증을 처리하는 것이 조금 더 자연스럽지 않을까하는 생각을 해보게 됩니다.
이번 글에는 구체적인 코드는 없지만 JWT를 이용해 어떤식으로 인증이 처리 되는지 그리고 JWT를 이용해서 클라이언트의 자격을 검증하는 프로세스가 어떻게 진행 되는지를 그림으로만 표현하도록 하겠습니다.
이 글에 있는 그림을 보고 CSR(Client Side Rendering) 방식의 애플리케이션에서 JWT를 이용해 인증 및 클라이언트의 자격 검증 로세스를 어떻게 코드로 구현할 수 있는지에 대한 인사이트를 얻어갈 수 있기를 바래봅니다.
JWT 인증 프로세스
[그림 1-1]의 JWT 인증 프로세스는 다음과 같습니다.
- 클라이언트가 최초 로그인 인증을 위해 username(이메일 등의 로그인 아이디)과 password를 request body에 실어서 전송합니다.
- 백엔드 애플리케이션 쪽으로 전송된 username과 password는
JwtAuthenticationFilter
에 전달되어JwtAuthenticationFilter
에서부터 클라이언트에 대한 인증 프로세스가 시작됩니다. JwtAuthenticationFilter
는UsernamePasswordAuthenticationFilter
를 확장해서 구현하면 됩니다.
- 백엔드 애플리케이션 쪽으로 전송된 username과 password는
JwtAuthenticationFilter
에서AuthenticationManager
의 구현 클래스인ProdiverManager
를 거쳐 인증되지 않은(unauthenticated) Authentication 객체가AuthenticationProvider
에게 전달됩니다.AuthenticationProvider
는 인증되지 않은(unauthenticated) Authentication 객체에 포함된 username을UserDetailsService
의 구현 클래스인MemberDetailsService
에게 전달합니다.loadUserByUsername(String username)
을 이용.
UserDetailsService
의 구현 클래스인MemberDetailsService
는 데이터베이스에서 사용자의 Credential(암호화 된 패스워드)을 조회한 뒤 조회한 Credential을 포함한UserDetails
를AuthenticationProvider
에게 리턴합니다.AuthenticationProvider
는 전달 받은UserDetails
에 포함된 Credential(암호화 된 패스워드)과 인증되지 않은(unauthenticated) Authentication 객체에 포함된 password를 암호화 해서 둘을 비교합니다.- 두 패스워드를 비교해서 검증에 성공하면 인증된(authenticated) Authentication 객체를
JwtAuthenticationFilter
에게 전달합니다. - 두 패스워드를 비교해서 검증에 실패하면 AuthenticationException을 throw합니다.
- 두 패스워드를 비교해서 검증에 성공하면 인증된(authenticated) Authentication 객체를
JwtAuthenticationFilter
는 전달 받은 인증된(authenticated) Authentication을 이용해 Access Token과 Refresh Token을 생성해 response header에 추가합니다.
JWT를 이용한 클라이언트 자격 검증 프로세스
클라이언트 측에서 JWT를 성공적으로 전달 받았다면 이제 전달 받은 Access Token을 이용해서 백엔드 애플리케이션의 API 엔드포인트에 접근할 수 있습니다.
[그림 1-2]의 JWT를 이용한 클라이언트 자격 검증 프로세스는 다음과 같습니다.
- 클라이언트는 백엔드 애플리케이션의 API 엔드포인트를 이용하기 위해 request를 전송할 때 마다 request header에 Access Token을 실어보냅니다.
JwtVerificationFilter
는 전달 받은 Access Token이 유효한 JWT인지를 검증하기 위해JwtTokenizer
에게 JWT 검증을 요청합니다.JwtTokenizer
는 Access Token의 Signature를 검증합니다.- Access Token이 유효한 JWT이면 Claims를 리턴합니다.
- Access Token이 유효하지 않으면 Exception을 throw합니다.
JwtVerificationFilter
는 전달 받은 Claims를 이용해 username과 role 정보를 포함한 Authentication 객체를SecurityContext
에 저장합니다.- 이제 인증된(authenticated) Authentication 객체가
SecurityContext
에 저장되어 있으므로DispatcherServlet
에 도달하기 전의 마지막 Security Filter까지 문제 없이 통과할 수 있습니다.
- 이제 인증된(authenticated) Authentication 객체가
DispatcherServlet
부터는 Spring MVC의 기본적인 요청 처리 흐름에서 알 수 있듯이 Controller까지 요청이 전달됩니다.
'Java Backend 개발자 되기 > Spring Security' 카테고리의 다른 글
JwtAuthorizationFilter에 try ~ catch 문이 있고, 없고의 차이 (2) | 2023.12.18 |
---|---|
Spring Security OAuth 2 컴포넌트 요약 (0) | 2023.01.26 |
JWT 자격 검증 시, SecurityContext는 언제 비워(clear)질까? (8) | 2023.01.19 |
Spring Security에서의 권한 부여 (Authorization) 처리 흐름 (0) | 2023.01.17 |
Spring Security에서의 인증(Authentication) 처리 흐름 (0) | 2023.01.17 |