티스토리 뷰
[Spring Boot] JWT 토큰 인증을 위한 두 가지 방법 (feat. API Gateway)
ch4njun 2021. 6. 19. 02:29JWT 토큰 인증방식을 위한 두 가지 방법을 소개하려고 한다.
첫 번째는 기본적으로 Spring Security를 이용해 인증을 구현하는 방식이고, 두 번째는 API Gateway에서 토큰 인증을 구현하는 방식이다. 차례로 살펴보고 그에 대한 장단점을 이야기해보도록 하자.
Spring Security를 이용한 방법
들어가기에 앞서 SecurityConfig, 즉 WebSecurity Configuration에 설정줘야 하는 코드를 먼저 살펴보자.
기본적으로 Spring Security를 사용해 로그인 시스템을 구현했기 때문에 관련코드와 함께 있다. 첫 번째 네모를 통해 해당 Filter에서 인터셉트할 URL(/api/*/**)와 인터셉트하지 않을 URL들을 정해주도록 구성한다.
즉, 로그인과 회원가입에 대해서는 토큰 인증을 수행할 필요가 없기때문에 제외시켜주기 위한 코드이다.
그러면 토큰인증이 필요한 Request(/api/*/**) 가 왔을 때 어떤 프로세스로 진행되는지 살펴보자.
1. JwtAuthenticationFilter의 attemptAuthentication()
아주 간단하게 HTTP Request의 Header에 Authorization값을 파싱해 UsernamePasswordAuthenticationToken을 상속한 PreJwtProcessingToken 객체(Authentication Object)를 생성해 Authentication Provider로 전송합니다.
2. JwtAuthenticationProvider의 authenticate()
실제로 인증과정에 대한 코드가 포함되어야 하는 곳이다. 여기선 크게 아래 2가지 동작을 수행한다.
- Token Black List 에 해당 토큰이 존재하는지 확인한다.
Token Black List는 로그아웃된 토큰이나 더 이상 사용되지 말아야하는 토큰사용을 막기 위한 목록입니다. - 해당 토큰을 Decode 한다.
이 과정에서 해당 토큰이 유효한지 판단하고 최종적으로 유효하다면 해당 토큰에 포함되어 있는 정보를 통해 UserContext 객체를 반환한다.
위 과정을 거친 후 정상적으로 UserContext가 반환되었다면 PostLoginAuthorizationToken(Authentication Object)를 반환한다.
3. JwtAuthenticationFilter의 successfulAuthentication()
위 이미지에서 볼 수 있듯이 Login 시스템을 구현할 때와 다르게 chain.doFilter(req, res) 가 있는 것을 확인할 수 있다. Login 시스템은 단순히 토큰만 반환해주면 되지만, 토큰 인증은 인증을 마친 후 기존 목적에 따라 Request 패킷이 Controller에 전달되어야 하기 때문에 이 구문을 "반드시" 적어줘야 한다.
인증이 성공한 경우 인증된 정보를 SecurityContext에 저장해야 한다. 이정도만 기억하고 일단 이 포스팅에서 중요한건 이게 아니기 때문에 넘어간다.
API Gateway를 이용한 방법 (Spring Cloud Gateway)
이 포스팅에서는 API Gateway에 대한 설명은 넘어가도록 한다.
내가 사용한 것은 Spring Cloud Gateway이다.
해당 API Gateway에는 총 3개의 서비스가 연결되어 있다. 그리고 이 3개의 서비스에 동일한 토큰 인증 방식을 구현해야 한다고 하자. 그러면 3개의 프로젝트를 열고 첫 번째 방법과 같이 Spring Security를 이용해 코드를 작성해야 된다.
하지만, API Gateway에 Filter를 추가할 수 있기 때문에 이러한 Filter를 이용한다면 다양한 기능을 공통적으로 적용할 수 있다. 즉, 3개의 서비스에 대해서 동일한 토큰 인증 코드를 한번에 작성할 수 있다는 것이다!!
그럼 간단한 코드를 살펴보자.
위 코드는 API Gateway 프로젝트에 존재하는 application.yml 파일이다. 위 코드는 API Gateway에 들어온 Request를 어느 서비스로 Routing할지 매핑시켜놓은 테이블이라고 보면 좋을듯 하다.
밑에 더 다양한 규칙들이 존재하지만 위 사지만 보면 총 3개의 규칙이 있는 것을 확인할 수 있고 위에서 부터 각각 1. 로그인, 2. 회원가입, 3. 나머지에 해당한다.
이 세가지 중에서 세번째에 대해서만 AutorizationHeaderFilter를 적용함으로써 로그인, 회원가입의 경우 토큰 인증과정을 거치지 않도록 구현한 것이다.
AuthorizationHeaderFilter
Filter를 작성하는 법에 대해서는 나중에 Filter에 대해서 깊이있게 다룰때 자세히 이야기하도록 한다. 코드를 보면 알겠지만 첫 번째 방법과 동일하게 Authorization Header에 대한 정보를 읽어오고 파싱해 Token에 대한 정보를 저장한다.
그리고 해당 Token이 올바른 토큰인지 검증하는 과정을 거치고 그 결과에 따라서 Exception을 반환한다.
정리
API Gateway를 이용하면 해당 게이트웨이에 연결되어 있는 서비스에 동일한 Filter를 적용할 수 있다. 이러한 기능을 활용한 것중 하나가 토큰 인증과정을 예시로 든 것이다.
하지만 개인적인 생각으로 아직 API Gateway를 이용해야 한다는 확신이 들지 않은 상태이다.
API Gateway의 Filter에서 토큰 인증과정을 처리해버리면 토큰에 저장되어 있는 UserContext정보(예를 들어 UserId)를 해당 서비스에서 사용할 수 없다. 또한 SecurityContext에 보관할 수 없기에 발생하는 문제점들도 있을 것 같다.
지금은 이렇게 구성하는 법도 있다는 것정도만 알아두고 더 다양한 코드를 살펴보고 추가적인 공부를 해야할 것 같다.
'Back-End > Spring Security' 카테고리의 다른 글
[Spring Security] Login 시스템 개발을 위한 두 가지 방법 (2) | 2021.06.18 |
---|---|
[Spring Boot] Spring Security(2) - JWT 토큰 인증 방식 구현 (0) | 2021.06.06 |
[Spring Boot] Spring Security (0) | 2021.05.21 |