[Spring Security] 로그인을 하기 위한 필터들(SecurityContextPersistence, RememberMe Filter)

WOOK JONG KIM·2022년 12월 1일
0

패캠_java&Spring

목록 보기
79/103
post-thumbnail

스프링은 아래와 같은 로그인 방식 지원

스프링이 인증 처리는 세션과는 별도로 동작하도록 설계
-> session 을 사용하건 사용하지 않건 같은 Authentication과 AuthenticationProvider 를 사용 가능

로그인 후 로그인을 유지시켜 주기 위한 방법 2가지

  1. Tomcat(Servlet Container)와 같은 웹 어플리케이션이 제공하는 세션 이용
  2. 세션이 사용하기 까다로운 경우 Redis, Hazelcast, Back 단의 Db 사용

스프링의 인증을 유지시켜주기 위해서는 session 을 이용하는 것이 개발자에게는 여러모로 편리
-> 이후 인증은 서버가 메모리를 소모해서 세션객체를 가지고 유지시켜주는 작업을 하도록 할 수 있다
(세션은 브라우저의 쿠키에 JSESSIONID 값을 심어놓고, 브라우저와 서버가 이 값을 주고 받으면서 세션을 보장받을 수 있음)

서버의 세션 정책과 스프링의 인증 체계가 서로 맞물려 동작하도록 하려면 SecurityContextPersistenceFilterRememberMeAuthenticationFilter, AnonymousAuthenticationFilter 등과 같이 인증을 보조해 주는 다른 필터들의 도움을 받아야 함
-> 이러한 필터를 통해 Security Context를 request가 처리 되는 동안 유지되게 할 수 있다


SecurityContextPersistenceFilter

SecurityContextPersistenceFilter

세션이 유지되고 있는 동안 시큐리티 컨텍스트가 유지되도록 도와줌

만약 세션이 만료된 이후라면, 당연히 그때는 재로그인을 해야함
-> 이를 귀찮아 할까봐 Remeberme 필터를 통해 토큰을 발급해서 자동로그인 되어 재로그인 없이 서비스를 계속 사용할 수 있음

이는 기본적으로 SecurityContext를 저장하는 Repository를 가지고 있음
-> 여러 구현체가 있지만, 기본적으로 이를 구현하고 있는 Http Session의 SecurityContextHolder를 저장하는 리포지토리를 사용하도록 되어 있음

한번 로그인 하고 나면은 그 이후 리퀘스트 부터는 session에서 컨텍스트를 가져다가 Security Context Holder에 넣어줌
-> 들어가 있기 때문에 로그인이 되어 있는 것으로 간주
ThreadLocal이 처리를 끝내고 나갈때는 SecurityContext를 클리어 해줌

즉 SecurityContextRepository 에 저장된 SecurityContext 를 Request의 LocalThread에 넣어주었다가 뺏는 역할을 한다

doFilter 메소드를 따라가보면 알 수 있다
-> 세션에 SecurityContext를 보관했다가 다음 request에서 넣어줌


RemeberMeAuthenticationFilter

쿠키에 보통 Rememberme 토큰을 심어둠

  • key : Hash 암/복호화에 사용할 키 값
  • token-validity-seconds : 토큰 유효 기간
  • authentication-success-handler-ref : 핸들러를 커스마이징 했다면 로그인 성공 후 수행할 로직
  • user-service-ref : UserDetailsService를 커스터마이징 했을 경우 주입

Remeberme Filter는 Remeberme service를 가짐
-> 이를 구현한 것이 AbstractRemebermeServices라는 공통 객체
-> 이를 확장한것이 TokenBasedRemeberMeServices와 PersistenceTokenBasedRememberMeServices

TokenBasedRemeberMeServices: 토큰을 브라우저에 저장(서버에 남기지 않음)(default)

  • 포멧 : 아이디:만료시간:Md5Hex(아이디:만료시간:비밀번호:인증키)
  • 만약 User가 password 를 바꾼다면 토큰을 쓸 수 없게 됩니다.
  • 기본 유효기간은 14일 이고 설정에서 바꿀 수 있습니다.
  • 약점 : 탈취된 토큰은 비밀번호를 바꾸지 않는한 유효기간동안 만능키가 됨

PersistenceTokenBasedRememberMeServices: 서버에 토큰을 저장해놓고 브라우저에 저장 후 사용

  • 포멧 : series:token
  • 토큰에 username이 노출되지 않고, 만료시간도 노출되지 않습니다. 만료시간은 서버에서 정하고 노출하지 않고 서버는 로그인 시간만 저장
  • series 값이 키가 됨
  • 대신 재로그인이 될 때마다 token 값을 갱신해 줌 -> 토큰이 탈취되어 다른 사용자가 다른 장소에서 로그인을 했다면 정상 사용자가 다시 로그인 할 때, CookieTheftException 이 발생하게 되고, 서버는 해당 사용자로 발급된 모든 remember-me 쿠키값들을 삭제하고 재로그인을 요청하게 됩
  • InmemoryTokenRepository 는 서버가 재시작하면 등록된 토큰들이 사라짐
    -> 자동로그인을 설정했더라도 다시 로그인을 해야 함
    -> 재시작 후에도 토큰을 남기고 싶다면 JdbcTokenRepository를 사용하거나 이와 유사한 방법으로 토큰을 관리
  • 로그아웃을 하면 다른 곳에 묻혀놓은 remember-me 쿠키값도 쓸모가 없게 됨
    -> 만약 다른 곳에서 remember-me로 로그인한 쿠키를 살려놓고 싶다면, series 로 삭제하도록 logout 을 수정

Remeberme로 로그인한 사용자는 UsernamePasswordAuthenticationToken 이 아닌 RememberMeAuthenticationToken 으로 서비스를 이용
-> 같은 사용자이긴 하지만, 토큰의 종류가 다르게 구분되어 있음


정리

series는 유저가 여러 브라우저에서 동시 접속할 수 있기 때문에 같은 유저라도 시리즈 값이 다르더라면 다른 브라우저로 인식

토큰으로 로그인을 할 때마다 시리즈의 토큰은 매번 갱신이됨

내가 마지막에 내려준 토큰으로 이 시리즈의 쿠키가 올라와야 서버는 연속적인 토큰임을 인지하고 계속해서 토큰을 갱신해주면서 쓸수 있게 해줌

profile
Journey for Backend Developer

0개의 댓글