LoginSignup
3
7

More than 5 years have passed since last update.

Spring Boot(2系)で Redis Session使用時に同一ユーザの他のセッション一覧を取得する。またそれを破棄する。

Last updated at Posted at 2018-07-29

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);
3
7
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
7