WebSecurityConfigurerAdapter を継承したConfigクラスに下記追加。
@Bean
public <S extends Session> SessionRegistry sessionRegistry(FindByIndexNameSessionRepository<S> sessionRepository) {
return new SpringSessionBackedSessionRegistry<>(sessionRepository);
}
生成した SessionRegistry を HttpSecurityの設定に追加する。
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests().antMatchers("/secure.html").authenticated().anyRequest().permitAll()
// login settings
.and().formLogin()
// ligout settings
.and().logout().logoutRequestMatcher(new AntPathRequestMatcher("/logout", "GET"))
// ここから追加分
.and().sessionManagement()
// 1ユーザあたりの許容する最大セッション数
// -1だと無制限
.maximumSessions(-1)
// 複数ログアウトに使用するSessionRegistry
.sessionRegistry(sessionRegistry(null))
// セッション切れになった場合に遷移するURL(設定しなかった場合、その画面でエラーメッセージが出る)
.expiredUrl("/login?logout");
}
設定は以上
あとはコントローラなりサービスなりでSessionRegistryを利用して同一ユーザのセッション一覧が取れる。
下記は現在ログイン中セッションを除いた同一ユーザセッションをログアウトさせる処理の例
@Autowired
private SessionRegistry sessionRegistry;
@RequestMapping("/logoutAnother")
public String logoutAnother(HttpSession currentSession) {
String sessionId = currentSession.getId();
Optional<Object> principal = Optional.ofNullable(SecurityContextHolder.getContext().getAuthentication())
.map(authentication -> authentication.getPrincipal());
if (principal.isPresent()) {
// 現在ログインしているユーザと同一ユーザのセッション一覧を取得
List<SessionInformation> sessions = sessionRegistry.getAllSessions(principal.get(), false);
for (SessionInformation session : sessions) {
if (sessionId.equals(session.getSessionId())) {
// 現在のセッションだけはログアウトしない
continue;
}
// セッション期限切れにしてログアウト
session.expireNow();
}
}
return "redirect:/";
}
sessionRegistry.getAllSessions
で第1引数に渡したユーザ情報と同じユーザのセッション一覧が取れる。
ログイン中のユーザではなく任意のユーザのセッション一覧を取りたい場合は第1引数に任意のユーザのIDを入れれば取れる。(管理者などが任意のユーザを強制ログアウトするなどを想定)
// 文字列
List<SessionInformation> sessions = sessionRegistry.getAllSessions("user", false);
// UserDetails: userDeails.getUsername() => "user"
List<SessionInformation> sessions = sessionRegistry.getAllSessions(userDeails, false);
// Principal: principal.getName() => "user"
List<SessionInformation> sessions = sessionRegistry.getAllSessions(principal, false);