Spring Security - OAuth2 && JWT (JSON Web Token) - 2

지난 글에서 https://infondgndg91.blogspot.com/2020/06/spring-security-oauth2-jwt-json-web.html
간단하게 OAuth 2.0 과 JWT (Json Web Token) 에 대해 정리를 해보았다.

이번 시간에는 OAuth 2.0 4가지 type 중 간단한, Resource Owner Password Credentials Grant 를 구현하려고 한다. 먼저 인증 서버에 대한 구현이다.

간단하게 개발 스펙을 정리해보자면,

Spring Boot 2.3.1.RELEASE 
Java 14

guava 와 commons 는 애용해서 넣었다. 그리고 auth0 의 JWT, DB 는 mysql 을 사용했다.
당연히 security 와 web 을 추가했다.

그밖에, 롬복, 데브툴, 컨피규레이션 프로세서는 개발 시 많은 유용함이 있어서 당연히 사용했다.


다음은 application.yml 이다. 우선 jwt 와 관련된 내용들이며, 다음은 DataSource 내용들이다. DB 는 AWS RDS 를 사용했고, write 와 read 클러스터 구성이다. 따라서 write 와 read 를 각각 설정해주었다. 로깅은 개발 시 로깅을 디테일하게 켜서 보려고 해놓은거라서 중요한 것은 아니다.




그렇다면, 먼저 DataSource 설정이다. JdbcTemplate 을 사용려고 각각의 DataSource 마다 JdbcTemplate 을 Bean 으로 이용했다.





그 다음, 시큐리티 설정을 확인하자. AuthenticationProvider 를 구현한 커스텀 JWTAuthenticationProvider 을 사용했다. OAuth 2.0 Token 기반 인증 방식을 사용하기 때문에, 세션은 당연히 StateLess 무상태이다. csrf, header, formlogin 모두 disabled 했다. AuthenticationEntryPoint 를 구현하는 핸들러와 AccessDeniedHandler 를 구현하는 핸들러를 통해서 401, 403 을 response 을 핸들링했다. /sign-in , /sign-up 을 제외한 모든 요청은 인증을 필요로한다. /member/test 의 경우만 자체적으로 테스트를 위해서 열어놓았다.

다음은 JWT 이다. newToken 메서드를 통해서 인증이 되었을 때 토큰을 발급해준다. JWTVerifier 을 통해서 만료된 토큰에 대해서 검사를 할 수 있다.

그렇다면, 이제 접근자가 자신을 인증하고 토큰을 발급받는 과정의 시작부터 따라가보자.

1. 먼저 접근자는 /sign-in 으로 username / password 를 담아 요청한다. 해당 정보가 담긴 객체가 AuthenticationRequest 이다. 해당 객체를 통해서 AbstractAuthenticationToken 을 상속 받은 JWTAuthenticationToken 을 생성한다. 그리고 AuthenticationManager 의  authenticate() 메서드를 통해서 해당 요청 인증처리를 시작한다. 즉, AuthenticationManager 을 구현한 ProviderManager 의 authenticate() 메서드를 실행하게 되고, 등록된 provider 를 가져와, authenticate() 메서드를 다시 호출한다. 해당 예제에서는 JWTAuthenticationProvider 를 구현했으므로, 해당 컴포넌트의 authenticate() 메서드가 호출되고 인증 로직을 타게 된다.



JWTAuthenticationProvider 에서 MemberService 를 통해서, 접근자의 username / password 를 통해서 정보를 가져오며, 유무에 따라 핸들링한다. 없는 경우 / 비밀 번호가 틀린 경우 / 있는 경우에 따라 각각 처리한다. 있는 경우 JWT 인 access_token 을 발급한다.


아래는 /sign-in 테스트이다. access_token 이 정상적으로 발급되었다.



이제 access_token 을 발급하는 서버를 완성했다. refresh_token 을 추가적으로 발급해도 된다.
인증 전략을 어떻게 취할지에 따라 refresh_token 발급 여부를 결정하면된다.
sliding session 기법을 사용하면 access_token 하나만 발급 해도 된다.  이 기법은 access_token 이 만료되지 않았다면, 자동으로 만료 시간을 갱신해 주는 기법이다.

refresh_token 과 sliding session 의 기법에는 각각 장단점이 있으므로, 상황에 따라 취사 선택을 잘 하면 된다.



다음은 GenericFilterBean 을 상속받는 커스텀 필터를 이용하여 Resource 서버를 구성하려고한다. 


resource server 의 핵심은 마찬가지로 security 를 이용한 jwt custom filter 이다. 모든 요청은 해당 필터를 통해서 인증을 하고, 인증이 되지 않을 경우, 지정한 EntryPoint 로 응답을 하게끔 하면 된다.
따라서 아래와 같이 custom filter 를 만든다.



아래와 같이 Security 설정에서 JWTAuthenticationTokenFilter 를 추가해주고, 또한 AuthenticationEntryPoint 를 구현하여 등록해주면 된다.


그리고 Resource Server 가 주문에 관련된 서버라고 가정했을 때 아래와 같이 ,
@AuthenticationPrincipal 어노테이션을 통해서 인증을 받은 접근자에 대한 정보를 사용할 수 있게된다.


만약, Resource Server 가 다양해진다면, 해당 설정을 모듈로써 관리하거나 Api Gateway 를 앞에 둘 수 있을 것 같다. 이는 상황에 따라 더 고민해보고 적용할 수 있을 것 같다.

댓글

이 블로그의 인기 게시물

About JVM Warm up

About idempotent

About Kafka Basic

About ZGC

sneak peek jitpack

Spring Boot Actuator readiness, liveness probes on k8s

About Websocket minimize data size and data transfer cost on cloud

About G1 GC

대학생 코딩 과제 대행 java, python, oracle 네 번째