Spring Security - UserDetailsService with Remember-me feature (PersistentTokenBasedRememberMeServices)

바로 지난 글(https://infondgndg91.blogspot.com/2020/06/spring-security-userdetailsservice-with.html)에서, 스프링 시큐리티에서 TokenBasedRememberMeServices 를 이용한 토큰 기반 Remember-Me 기능에 대해 알아보았다.

이번글에서는, PersistentTokenBasedRememberMeServices 를 이용한 영구 토큰 기반 Remember-Me 에 대해서 정리해보려고 한다.

먼저 영구 토큰 기반 Remember-Me 기능을 사용하기 위해선 말 그대로 토큰을 저장할 저장소가 필요하다. 나의 경우 MariaDB 를 사용했다.

Persistent Token Based 는 Token Based 와 다르게 시그니처를 검증하지 않는다. 대신, 토큰 저장소에 일한 토큰이 존재하는지 확인한다. Persistent Token Based Cookie 는 아래와 같은 요소를 포함한다.

  • 시리즈 식별자 (Series Identifier) : 사용자의 초기 로그인을 식별하며, 사용자가 세션에 자동으로 로그인될 때마다 값이 항상 동일하다.
  • 토큰 값 : 사용자가 Remember-Me 기능을 사용해 인증될 때마다 변경되는 고유한 값이다.
아래 다이어그램을 보면, Remember-Me 쿠키가 전송되면, 스프링 시큐리티는 전송된 쿠키의 시리즈 식별자를 통해서, PersistentTokenRepository 에서 예상되는 토큰값을 찾는다. 찾은 토큰의 값과 전송된 쿠키의 값을 비교하여 일치여부를 통해 인증을 한다.

사용자가 전송한 시리즈 식별자와 일치하는 값이 데이터베이스에 존재하지만 토큰 값이 일치하지 않는 경우 누군가가 Remember-Me 쿠키를 도용하고 있다고 간주할 수 있다. 해당 경우, 스프링 시큐리티는 관련된 Remember-Me 토큰을 폐기하고 사용자에게 해당 세션의 탈취 가능성을 경고한다. 이 경우 스프링 시큐리티는 관련된 모든 세션을 종료한다.



지난글에서도 언급했지만, Spring security 의 Remember-Me 기능을 사용하기 위해서는 UserDetailsService 를 사용해야만 한다.

아래의 PersistentTokenBasedRememberMeServices 를 보면 processAutoLoginCookie() 메서드의 맨 아래 return 문을 보자. getUserDetailsService().loadUserByUsername() 메서드를 호출하고 있다.

이전글에서도 언급했지만, AbstractRememberMeServices 를 상속받는 커스텀 영구 토큰 기반 리멤버 미 서비스를 만들면 UserDetailsService 를 사용하지 않아도 될 지 모른다. (시도해보지 않아서 확신하기 어렵다.)

그렇다면, 설정으로 넘아간다.
rememberMe 메서드의 새로운 tokenRepository 메서드를 인식하도록 하면 된다.

아래는 UserDetailsManager 를 구현한 custom UserDetailsService 이다.
UserDetailsManager 는 UserDetailsService 를 상속받는다.

tokenRepository 는 아래와 같이, PersistentTokenRepository 를 구현했다.

추가적으로 PersistTokenRepository 에서 RequestContextHolder 를 통해서 request 의 ip 추출을 통해 좀더 구체적으로 핸들링이 가능하다.


아래는 데이터베이스 저장할 RememberMeToken Entity 이다.

만료된 Remember-Me 세션 정리

영구 토큰 기반 Remember-Me 기능의 단점은 만료된 세션을 정리할 수 있는 빌트인 지원이 없다는 점이다. 따라서 만료된 세션을 정리하는 백그라운드 프로세스를 구현해야 된다. 예를 들어 스케쥴링 기법을 통해서 주기적으로 만료일이 지난 쿠키들을 delete() 해주는 로직이 필요하다.




추가적으로 진행해 보고 포스팅 해 볼 것.


custom RememberMeServices
  1. UserDetailsService 를 사용하지 않고 Remember-Me 기능을 사용할 수 있는지 구현해보기.


댓글

이 블로그의 인기 게시물

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 네 번째