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 인증 프로세스

[그림 1-1]의 JWT 인증 프로세스는 다음과 같습니다.

  • 클라이언트가 최초 로그인 인증을 위해 username(이메일 등의 로그인 아이디)과 password를 request body에 실어서 전송합니다.
    • 백엔드 애플리케이션 쪽으로 전송된 username과 password는 JwtAuthenticationFilter에 전달되어 JwtAuthenticationFilter에서부터 클라이언트에 대한 인증 프로세스가 시작됩니다.
    • JwtAuthenticationFilterUsernamePasswordAuthenticationFilter를 확장해서 구현하면 됩니다.
  • JwtAuthenticationFilter에서 AuthenticationManager의 구현 클래스인 ProdiverManager를 거쳐 인증되지 않은(unauthenticated) Authentication 객체가 AuthenticationProvider에게 전달됩니다.
  • AuthenticationProvider는 인증되지 않은(unauthenticated) Authentication 객체에 포함된 username을 UserDetailsService의 구현 클래스인 MemberDetailsService에게 전달합니다.
    • loadUserByUsername(String username)을 이용.
  • UserDetailsService의 구현 클래스인 MemberDetailsService는 데이터베이스에서 사용자의 Credential(암호화 된 패스워드)을 조회한 뒤 조회한 Credential을 포함한 UserDetailsAuthenticationProvider에게 리턴합니다.
  • AuthenticationProvider는 전달 받은 UserDetails에 포함된 Credential(암호화 된 패스워드)과 인증되지 않은(unauthenticated) Authentication 객체에 포함된 password를 암호화 해서 둘을 비교합니다.
    • 두 패스워드를 비교해서 검증에 성공하면 인증된(authenticated) Authentication 객체를 JwtAuthenticationFilter에게 전달합니다.
    • 두 패스워드를 비교해서 검증에 실패하면 AuthenticationException을 throw합니다.
  • JwtAuthenticationFilter는 전달 받은 인증된(authenticated) Authentication을 이용해 Access Token과 Refresh Token을 생성해 response header에 추가합니다.

 

 

JWT를 이용한 클라이언트 자격 검증 프로세스

[그림 1-2] 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까지 문제 없이 통과할 수 있습니다.
  • DispatcherServlet부터는 Spring MVC의 기본적인 요청 처리 흐름에서 알 수 있듯이 Controller까지 요청이 전달됩니다.

+ Recent posts

출처: http://large.tistory.com/23 [Large]