고인물을 지양하는 블로그

[Spring Security] 토큰기반 RememberMe 본문

카테고리 없음

[Spring Security] 토큰기반 RememberMe

yunjaeGong 2021. 10. 28. 02:27

서버는 어떻게 각 사용자를 구별할까?

서버는 세션 정보를 통해 사용자를 구별하고, 각 사용자의 정보를 취급한다.

 

사용자 정보는(id, 비밀번호 등..) 서버에 저장하고, 유저 브라우저에는 sessionId를 개인 식별자로 사용한다. 이렇게 발급된 sessionId를 요청 헤더에 담아 전달하면 서버에서 사용자를 식별 할 수 있다.

RememberMe 서비스란

웹사이트가 세션 간 사용자의 정보를 기억하는(유지하는) 것을 뜻한다. 세션 만료나 세션 정보 유실 (e.g. 쿠키 삭제) 등으로 새로운 세션이 생성되는 경우에서도 재 로그인 없이 웹에서 기존 사용하던 사용자의 정보가 유지되는 것을 말한다.

 

따라서 RememberMe가 적용된 웹사이트는 유저가 명시적으로 로그아웃 하지 않는 이상 로그인 정보가 세션만 사용할 때 보다 길게 유지된다.

 

내부적으로 RememberMe 서비스는 session 만료 등 변화에도 일정 기간동안 세션 변화 시 필요했던 인증(로그인과 같은) 과정을 대신해 준다고 볼 수 있다.

 

도큐먼트에서는 RememberMe 서비스의 구현 방법 두 가지를 소개하고 있다.

  • PersistentTokenBasedRememberMeServices
  • TokenBasedRememberMeServices

이 프로젝트에서는 두 번째이자 아마도 가장 흔하게 사용되는 방법일 토큰 기반(쿠키에 RememberMeAuthenticationToken을 저장) 구현 방법을 사용했다.


RememberMe 적용

스프링 시큐리트는 RememberMe 기능을 제공하고 있다. 

 

로그인 페이지를 생성하고, name이 remember-me인 checkbox를 생성한다. (파라미터 기본값이 remember-me)

<input type="checkbox" name="remember-me">remember me</input>

 

 

RememberMe 서비스는 스프링 시큐리티가 제공하는 기능중 하나로, WebSecurityConfig 클래스에서 rememberMe() 추가로 적용할 수 있다.

 

remember me checkbox를 체크한 후 로그인을 진행하면 정상적으로 rememberMe 토큰이 발급된 것을 확인할 수 있다.

 

 

session이 유실된 경우를 가정하고 session 쿠키를 삭제한 후 인증이 필요한 페이지를 요청하니 다음과 같은 에러가 발생했다.

말 그대로 userDetailsService를 찾을 수 없어 발생하는 오류였다. 오류는 TokenBasedRememberMeService 파일의 아래 breakpoint 부분에서 발생했다.

 

프로젝트에서 유저 정보를 담기 위해 userDetails를 상속하는 커스텀 userDetails인 principalDetails 클래스를 사용했는데, PrincipalDetailsService를 등록하지 않아 발생한 문제였다.

 

이미 서비스로 등록된 principalDetailsService를 WebSecurity 설정에 사용할 수 있게 주입하도록 한다.

주입된 principalDetailsService를 rememberMe의 userDetailsService로 등록한다.

 

이렇게 하면 인증이 필요한 페이지에 정상적으로 접근 가능하고, 삭제했던 JSESSIONID가 다시 부여되고, 세션 변화에도 로그인이 유지(같은 사용자로 인식)된다.


왜 이렇게 하면 될까? 

단순히 RememberMeService의 UserDetailsService 기본 설정 때문이었다. WebSecurityCofigurerAdapter.configure(AuthenticationManagerBuilder)를 사용할 때 등록된 공유 오브젝트 중 UserDetailsService를 사용해 UserDetailsService를 찾지 못해 발생함 문제였던 것 같다. 

 

RememberMeConfigurer.java

그럼 configure(AuthenticationManagerBuilder)에서 principalDetailsService를 등록했더라면 rememberMeConfigurer에 principalDetailsService를 따로 추가하지 않아도 된다는 말이 된다.

configure(AuthenticationManagerBuilder)에서 principalDetailsService를 등록하니 rememberMe에 직접추가를 하지 않더라도 정상적으로 동작했다.

 

 

Comments