SpringSecurity(セッション数管理)
はじめに
こんにちは!
オアシステクノロジーズの山本です。
SpringBoot + SpringSecurity でセッション数管理ではまったので、その内容を共有します。
目次
- 前提
- セッション数管理
- 問題点
- 解決策
- まとめ
1.前提
SpringBoot + SpringSecurity でセッション数(Redis※ElasticCashe)管理を行う前提で記載しています。
SpringBoot 3.2.3
SpringSecurity 6.2.2
SpringDataRedis 3.2.3
2.セッション数管理
SpringSecurity でセッション数管理を行う場合、以下のような設定を行います。
今回は同一ユーザーのセッション数を1つ、後勝ち(新しいログインが既存のセッションを無効にする)とする設定を行います。
※あくまでイメージです。application.ymlの設定は省略しています。
@Configuration
@EnableWebSecurity
@EnableRedisHttpSession
public class SecurityConfig {
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http
.sessionManagement(session -> session
.sessionConcurrency(concurrent -> concurrent
.maximumSessions(1)
.maxSessionsPreventsLogin(false) // false = 後勝ち
.expiredUrl("/login?expired")
)
)
.formLogin(form -> form
.loginPage("/login")
.permitAll()
);
return http.build();
}
@Bean
public HttpSessionEventPublisher httpSessionEventPublisher() {
return new HttpSessionEventPublisher();
}
}
3.問題点
SpringSecurityでセッション数管理を行う場合、セッション情報を保持するための SessionRegistry が使われます。
デフォルトのままだと、SessionRegistryImpl がDIされ、このクラスはメモリ上にセッション情報を保持します。
このため、アプリケーションが複数のインスタンスで動作する場合、セッション情報が共有されないため、セッション数管理が正しく行われません。
4.解決策
セッション情報を共有するためには、SessionRegistry の実装クラスを変更する必要があります。
SessionRegistry の実装クラスをSpringSessionBackendSessionRegistryへ変更することで、セッション情報を共有し、複数のインスタンスで正しくセッション数管理を行うことができます。
@EnableRedisIndexedSessionRepository
public class SecurityConfig {
~省略~
@Bean
public <S extends Session> SessionRegistry sessionRegistry(FindByIndexNameSessionRepository<S> sessionRepository) {
return new SpringSessionBackendSessionRegistry<>(sessionRepository);
}
~省略~
5.まとめ
SpringSecurityのセッション数管理について、SpringBootで良しなにやってくれていると思いきや、冗長構成への対応の考慮が必要でした。
ローカル環境やテスト環境(単一インスタンス)だとなかなか気付けない事象なのでお気を付けを・・・!
Discussion