@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception{
http.csrf().disable().cors().disable()
.authorizeRequests(request -> request
.requestMatchers(PathRequest.toStaticResources().atCommonLocations()).permitAll()
.dispatcherTypeMatchers(DispatcherType.FORWARD).permitAll()
.mvcMatchers("/images/**", "/events/**", "/members/**", "/lorahost/**", "/sneat/**", "/img/**", "/club/**").permitAll()
.mvcMatchers("/admin/**").hasRole("ADMIN")
.anyRequest().authenticated()
).formLogin(login -> login
.loginPage("/members/login")
.usernameParameter("email")
.passwordParameter("password")
.failureUrl("/")
//.successHandler(loginSuccessHandler)
//.defaultSuccessUrl("/events", true) defaultSuccessUrl설정되면 loginsuccessHandler 작동 안 함
.permitAll()
).logout(logout -> logout
.logoutSuccessUrl("/"))
.sessionManagement()
.maximumSessions(1)
.maxSessionsPreventsLogin(false);
return http.build();
}
사용자 로그인 시 UsernamePasswordAuthenticationFilter
내 로그인 로직 수행 이중 OnAuthentication메소드 내에 특정 Principal(Id)에 대한 session정보를 모두 불러온 후 허용된 session 개수와 비교하는 부분이 있음
허용 가능한 session 개수를 초과한 경우 allowableSessionsExceeded()를 호출함
여기서 세션의 전부 expired처리를 함 분석 당시 메모리에 아래와 같은 session정보들이 있었는데 전부 expired된 상태
"BC35C96D6FF711B831812CC10071A01A" -> {SessionInformation@18783}
"4A6A11CAF73103B2C977EDDA3727D5A9" -> {SessionInformation@17545}
"3F7E23EEA2A96DC1A0DF392D98AB2F7A" -> {SessionInformation@17892}
"6F5705C42B79BB92A819A6A79D78538D" -> {SessionInformation@17546}
"C143154293CFF220EC64BCB319104D1D" -> {SessionInformation@17572}
"A4718C6B925A45B754EB2BF867296D4B" -> {SessionInformation@18574}
"141BB2B060F9D37862361E8ACC7A5520" -> {SessionInformation@17812}
그 다음 새로운 세션을 SessionRegistry에 등록하는데, SessionRegistry 구현체인 SessionRegistyImpl에는 {Pricipal : SessionId set}으로된 ConcurrentMap이 있음(getAllSessions()가 반환하는 값이 여기에 있는 SessionId Set을 이용함) 또한 {SessionId : SessionInfo}로 구성된 sessionIds Map이 있음. 여기서 신규 로그인한 사용자의 session을 Pricipal에 등록함
만약 이전에 로그인했던 사용자가 다시 사이트에 접근하면 ConcurrentSessionFilter에서는 해당 session 계정에 대한 logout처리를 진행하고 추가 filter을 진행하지 않고 반환함