Spring Boot Security 사용자별 동시접속자 수 제어

2023. 6. 30. 09:15웹개발/Spring Boot

728x90
        @Bean
        public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {

                return http
                // .addFilterBefore(new CustomAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class)
                .httpBasic().and()
                .sessionManagement((sessionManagement) ->
                        sessionManagement
                        // .sessionAuthenticationStrategy(sessionControlStrategy())
                        // .sessionCreationPolicy(SessionCreationPolicy.STATELESS)
                        // .sessionConcurrency((sessionConcurrency) -> sessionConcurrency
                        //         // .maximumSessions(1)
                                // .maxSessionsPreventsLogin(true)
                                // .expiredUrl("/login?expired")
                                // .sessionRegistry(sessionRegistry())
                        // )
                        .sessionFixation()
                        .newSession()
                        .sessionAuthenticationStrategy(concurrentSession())
                ).authorizeRequests((authorizeRequests) -> authorizeRequests
                        .mvcMatchers("/rest/*").permitAll()
                        .mvcMatchers("/", "/welcome", "/index","/sessionExpired", "/sample/**").permitAll()
//                        .anyRequest().authenticated()
                ).formLogin((formLogin) -> formLogin
                        .loginPage("/login")
                        .successForwardUrl("/")
                        .successHandler(new CustomAuthenticationSuccess())
                        .permitAll()
                ).logout((logout) -> logout
                        .logoutRequestMatcher(new AntPathRequestMatcher("/logout"))
                        .logoutSuccessUrl("/")
                        .addLogoutHandler((request, response, authentication) -> { 
                                HttpSession session = request.getSession();
                                SessionInformation sessionInformation = sessionRegistry().getSessionInformation(session.getId());
                                if(sessionInformation != null && !sessionInformation.isExpired()) {
                                        sessionInformation.expireNow();
                                }
                                
                            })
                )
                .rememberMe((rememberMe) -> rememberMe
                        .userDetailsService(userDetailsService)
                        .tokenRepository(tokenRepository())
                )
                .addFilter(concurrentSessionFilter())
                .build();
        }

 

.sessionAuthenticationStrategy(concurrentSession()) 이부분을 추가해주고
 
        @Bean
        public CompositeSessionAuthenticationStrategy concurrentSession() {
    
            CustomConcurrentSessionControlAuthenticationStrategy concurrentAuthenticationStrategy = new CustomConcurrentSessionControlAuthenticationStrategy(sessionRegistry());
    //		concurrentAuthenticationStrategy.setMaximumSessions(1);
    //		concurrentAuthenticationStrategy.setExceptionIfMaximumExceeded(true);
                List<SessionAuthenticationStrategy> delegateStrategies = new ArrayList<SessionAuthenticationStrategy>();
                delegateStrategies.add(concurrentAuthenticationStrategy);
                delegateStrategies.add(new SessionFixationProtectionStrategy());
                delegateStrategies.add(new RegisterSessionAuthenticationStrategy(sessionRegistry()));
    
                return new CompositeSessionAuthenticationStrategy(delegateStrategies);
        }

 

        @Bean
        public SessionRegistry sessionRegistry() {
          return new SessionRegistryImpl();
        }

 

        @Bean
        ConcurrentSessionFilter concurrentSessionFilter() {
            CustomSessionInformationExpiredStrategy redirectStrategy = new CustomSessionInformationExpiredStrategy("/login");
            CustomConcurrentSessionFilter concurrentSessionFilter = new CustomConcurrentSessionFilter(sessionRegistry(), redirectStrategy);
            return concurrentSessionFilter;
        }
SecurityConfig 설정 Class에 추가하여 설정
 
public class CustomConcurrentSessionFilter extends ConcurrentSessionFilter {

	public CustomConcurrentSessionFilter(SessionRegistry sessionRegistry) {
		super(sessionRegistry);
	}

	public CustomConcurrentSessionFilter(SessionRegistry sessionRegistry, SessionInformationExpiredStrategy sessionInformationExpiredStrategy) {
		super(sessionRegistry, sessionInformationExpiredStrategy);
	}

	@Override
	public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
		super.doFilter(req, res, chain);
	}

}
ConcurrentSessionFilter 를 상속받아 구현하고
 
 
public class CustomConcurrentSessionControlAuthenticationStrategy extends ConcurrentSessionControlAuthenticationStrategy{
    public CustomConcurrentSessionControlAuthenticationStrategy(SessionRegistry sessionRegistry) {
        super(sessionRegistry);
    }


    //최대 세션 수 적용
    @Override
    protected int getMaximumSessionsForThisUser(Authentication authentication) {
        // authentication.getPrincipal()
        // authentication.getAuthorities()
        // 사용자별 최대 세션수 설정하면 될듯
        // return 8;
        UserAccount account = (UserAccount)authentication.getPrincipal();
        return account.getAccount().getSessionCount()+1;
    }
    
}
ConcurrentSessionControlAuthenticationStrategy 를 상속받아 구현한곳에  
 
getMaximumSessionsForThisUser를 오버라이드 해서 사용자별 세션수를 가져와 비교(해당부분에서 DB를 조회해서 비교할수있음)
 
728x90
반응형