작성
·
499
0
안녕하세요 ^^.
강의 잘듣고 있습니다.
리멤버미 토큰 관련해서 질문이 있습니다.
스프링 시큐리티 리멤버미 기능을 이용하고 있는데요, 토큰 저장소는 DB 에 저장을 해놓고요.
하지만 스프링 application 을 restart 하게 되면 .CookieTheftException Exception 이 터집니다. 디버깅해보니, 이전에 저장되어 있던 Token value 와 새로 인입된 Token Value 가 일치하지 않더라고요..
테스트 순서는 아래와 같습니다.
1. 리멤버미를 이용한 로그인 후 로그인 성공
2. DB 및 쿠키 remember-me 확인 완료
3. Springboot app 재시작
4. front 페이지 새로고침
5. RememberMeTokenRepository -> updateToken 메소드 호출 되면서 token value DB update
( 이때 페이지 새로고침했다고 토큰이 새로 발행되는게 맞나요? 토큰 expire 시간이 지나지도 않았는데)
6. 기존 token value 와 신규 token value 불일치로 인한 RememberMeTokenRepository -> removeUserTokens 메소드 호출되면서 token 삭제
7. .CookieTheftException 예외 터짐
일단 어플리케이션 재기동 이후 페이지 새로고침을 하는 순간 기존에 토큰 값이 아닌 새로운 값이 업데이트 되는데, 업데이트된 토큰 값 과 기존의 토큰 값이 불일치 하니 당연히 에러가 터지겠죠..
근데 왜 업데이트가 되는지 이해가 잘 안되네요..
혹시 어플리케이션 재기동하게되면 리멤버미 기능을 이용해서 이미 로그인되어 있는 유저들은 어떻게 처리해야 좋을까요?
혹시 몰라 아래 로그 달아드릴게요..
강의 너무 감사합니다.
2021-07-16 16:10:09.061 INFO 18296 --- [nio-8080-exec-1] c.m.c.r.RememberMeTokenRepository : remember-me token 획득
Hibernate:
select
rememberme0_.series as series1_1_,
rememberme0_.last_used as last_use2_1_,
rememberme0_.token as token3_1_,
rememberme0_.username as username4_1_
from
persistent_logins rememberme0_
where
rememberme0_.series=?
2021-07-16 16:10:09.262 INFO 18296 --- [nio-8080-exec-1] c.m.c.r.RememberMeTokenRepository : remember-me token 획득 tokne oulEuy+jZS+XqpkJfzYwBw==
2021-07-16 16:10:09.297 INFO 18296 --- [nio-8080-exec-1] c.m.c.r.RememberMeTokenRepository : remember-me token 업데이트 [ddCMgrk5Gm0hEqiH4LuvaQ==] [55vHBaBrKjGiA039ZzOH4w==]
Hibernate:
select
rememberme0_.series as series1_1_,
rememberme0_.last_used as last_use2_1_,
rememberme0_.token as token3_1_,
rememberme0_.username as username4_1_
from
persistent_logins rememberme0_
where
rememberme0_.series=?
Hibernate:
update
persistent_logins
set
last_used=?,
token=?,
username=?
where
series=?
Hibernate:
select
member0_.id as id1_18_,
member0_.created_at as created_2_18_,
member0_.updated_at as updated_3_18_,
member0_.access_token as access_t4_18_,
member0_.access_yn as access_y5_18_,
member0_.account_type as account_6_18_,
member0_.activated as activate7_18_,
member0_.birth_date as birth_da8_18_,
member0_.branch as branch9_18_,
member0_.comment as comment10_18_,
member0_.email_address as email_a11_18_,
member0_.gender as gender12_18_,
member0_.group_name as group_n13_18_,
member0_.guide_count as guide_c14_18_,
member0_.last_accessed_at as last_ac15_18_,
member0_.name as name16_18_,
member0_.password as passwor17_18_,
member0_.phone as phone18_18_,
member0_.point as point19_18_,
member0_.position as positio20_18_,
member0_.refresh_token as refresh21_18_
from
tb_member member0_
where
member0_.email_address=?
2021-07-16 16:10:09.403 ERROR 18296 --- [nio-8080-exec-1] o.a.c.c.C.[.[.[/].[dispatcherServlet] : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception
java.lang.NullPointerException: null
at org.springframework.security.authentication.AccountStatusUserDetailsChecker.check(AccountStatusUserDetailsChecker.java:41)
at org.springframework.security.web.authentication.rememberme.AbstractRememberMeServices.autoLogin(AbstractRememberMeServices.java:137)
at org.springframework.security.web.authentication.rememberme.RememberMeAuthenticationFilter.doFilter(RememberMeAuthenticationFilter.java:104)
at org.springframework.security.web.authentication.rememberme.RememberMeAuthenticationFilter.doFilter(RememberMeAuthenticationFilter.java:92)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336)
at org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter.doFilter(SecurityContextHolderAwareRequestFilter.java:149)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336)
at org.springframework.security.web.savedrequest.RequestCacheAwareFilter.doFilter(RequestCacheAwareFilter.java:63)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336)
at org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:218)
at org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:212)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336)
at org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:103)
at org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:89)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336)
at org.springframework.security.web.header.HeaderWriterFilter.doHeadersAfter(HeaderWriterFilter.java:90)
at org.springframework.security.web.header.HeaderWriterFilter.doFilterInternal(HeaderWriterFilter.java:75)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336)
at org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:110)
at org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:80)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336)
at org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter.doFilterInternal(WebAsyncManagerIntegrationFilter.java:55)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336)
at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:211)
at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:183)
at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:358)
at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:271)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162)
at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:100)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162)
at org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:93)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162)
at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:202)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:97)
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:542)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:143)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:78)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:357)
at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:374)
at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:65)
at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:893)
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1707)
at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)
at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128)
at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628)
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
at java.base/java.lang.Thread.run(Thread.java:834)
2021-07-16 16:10:09.412 INFO 18296 --- [nio-8080-exec-1] c.m.c.r.RememberMeTokenRepository : remember-me token 획득
Hibernate:
select
rememberme0_.series as series1_1_,
rememberme0_.last_used as last_use2_1_,
rememberme0_.token as token3_1_,
rememberme0_.username as username4_1_
from
persistent_logins rememberme0_
where
rememberme0_.series=?
2021-07-16 16:10:09.421 INFO 18296 --- [nio-8080-exec-1] c.m.c.r.RememberMeTokenRepository : remember-me token 획득 tokne 55vHBaBrKjGiA039ZzOH4w==
2021-07-16 16:10:09.441 INFO 18296 --- [nio-8080-exec-1] c.m.c.r.RememberMeTokenRepository : remember-me token 삭제 11
Hibernate:
select
rememberme0_.series as series1_1_,
rememberme0_.last_used as last_use2_1_,
rememberme0_.token as token3_1_,
rememberme0_.username as username4_1_
from
persistent_logins rememberme0_
where
rememberme0_.username=?
Hibernate:
delete
from
persistent_logins
where
series=?
2021-07-16 16:10:09.492 ERROR 18296 --- [nio-8080-exec-1] o.a.c.c.C.[.[.[/].[dispatcherServlet] : Servlet.service() for servlet [dispatcherServlet] threw exception
org.springframework.security.web.authentication.rememberme.CookieTheftException: Invalid remember-me token (Series/token) mismatch. Implies previous cookie theft attack.
at org.springframework.security.web.authentication.rememberme.PersistentTokenBasedRememberMeServices.processAutoLoginCookie(PersistentTokenBasedRememberMeServices.java:113)
at org.springframework.security.web.authentication.rememberme.AbstractRememberMeServices.autoLogin(AbstractRememberMeServices.java:136)
at org.springframework.security.web.authentication.rememberme.RememberMeAuthenticationFilter.doFilter(RememberMeAuthenticationFilter.java:104)
at org.springframework.security.web.authentication.rememberme.RememberMeAuthenticationFilter.doFilter(RememberMeAuthenticationFilter.java:92)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336)
at org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter.doFilter(SecurityContextHolderAwareRequestFilter.java:149)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336)
at org.springframework.security.web.savedrequest.RequestCacheAwareFilter.doFilter(RequestCacheAwareFilter.java:63)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336)
at org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:218)
at org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:212)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336)
at org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:103)
at org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:89)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:103)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336)
at org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:110)
at org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:80)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:103)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336)
at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:211)
at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:183)
at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:358)
at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:271)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162)
at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:100)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:103)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:103)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162)
at org.apache.catalina.core.ApplicationDispatcher.invoke(ApplicationDispatcher.java:710)
at org.apache.catalina.core.ApplicationDispatcher.processRequest(ApplicationDispatcher.java:459)
at org.apache.catalina.core.ApplicationDispatcher.doForward(ApplicationDispatcher.java:384)
at org.apache.catalina.core.ApplicationDispatcher.forward(ApplicationDispatcher.java:312)
at org.apache.catalina.core.StandardHostValve.custom(StandardHostValve.java:398)
at org.apache.catalina.core.StandardHostValve.status(StandardHostValve.java:257)
at org.apache.catalina.core.StandardHostValve.throwable(StandardHostValve.java:352)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:177)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:78)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:357)
at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:374)
at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:65)
at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:893)
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1707)
at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)
at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128)
at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628)
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
at java.base/java.lang.Thread.run(Thread.java:834)
2021-07-16 16:10:09.493 ERROR 18296 --- [nio-8080-exec-1] o.a.c.c.C.[Tomcat].[localhost] : Exception Processing ErrorPage[errorCode=0, location=/error]
답변 1
0
제가 강의에서 리멤버 미 관련해서 DB 를 사용하는 방식은 몇가지 해결해야 할 이슈가 있어서 강의에서 제외했습니다.
일단 깃헙 소스 공유가 가능할까요?
DB 환경까지 갖추어 테스트하기가 쉽지는 않겠지만 직접 어플리케이션을 구동하지 않고서 답변을 드리기가 어려운 점이 있습니다.