1. 序章

Spring Securityは、Springベースのアプリケーションを保護するための標準です。 ログインやログアウトなど、ユーザーの認証を管理するためのいくつかの機能があります。 

このチュートリアルでは、焦点を当てます SpringSecurityを使用した手動ログアウト。

読者はすでに標準を理解していると想定します 春のセキュリティログアウトプロセス。

2. 基本的なログアウト

いつ ユーザーがログアウトを試みると、現在のセッション状態にいくつかの影響があります。 2つのステップでセッションを破棄する必要があります。

  1. HTTPセッション情報を無効にします。
  2. 認証情報が含まれているため、SecurityContextをクリアします。

これらの2つのアクションは、 SecurityContextLogoutHandler。

それを実際に見てみましょう:

@Configuration
public class DefaultLogoutConfiguration extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
          .logout(logout -> logout
            .logoutUrl("/basic/basiclogout")
            .addLogoutHandler(new SecurityContextLogoutHandler())
          );
    }
}

SecurityContextLogoutHandlerはデフォルトでSpringSecurityによって追加されることに注意してください。ここでは、わかりやすくするためにこれを示しています。

3. クッキークリアログアウト

多くの場合、ログアウトでは、ユーザーのCookieの一部またはすべてをクリアする必要があります。

これを行うには、すべてのCookieをループし、ログアウト時に期限切れにする独自のLogoutHandlerを作成できます。

@Configuration
public class AllCookieClearingLogoutConfiguration extends WebSecurityConfigurerAdapter {
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
          .logout(logout -> logout
            .logoutUrl("/cookies/cookielogout")
            .addLogoutHandler((request, response, auth) -> {
                for (Cookie cookie : request.getCookies()) {
                    String cookieName = cookie.getName();
                    Cookie cookieToDelete = new Cookie(cookieName, null);
                    cookieToDelete.setMaxAge(0);
                    response.addCookie(cookieToDelete);
                }
            })
          );
    }
}

実際、SpringSecurityはCookieClearingLogoutHandler を提供しています。これは、Cookieを削除するためのすぐに使用できるログアウトハンドラーです。

4. Clear-Site-Dataヘッダーログアウト

同様に、特別なHTTP応答ヘッダーを使用して同じことを実現できます。 ここで、Clear-Site-Dataヘッダーが機能します。

基本的に、 Clear-Data-Site ヘッダーは、要求元のWebサイトに関連付けられている閲覧データ(Cookie、ストレージ、キャッシュ)をクリアします。

@Configuration
public class ClearSiteDataHeaderLogoutConfiguration extends WebSecurityConfigurerAdapter {

    private static final ClearSiteDataHeaderWriter.Directive[] SOURCE = 
      {CACHE, COOKIES, STORAGE, EXECUTION_CONTEXTS};

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
          .logout(logout -> logout
            .logoutUrl("/csd/csdlogout")
            .addLogoutHandler(new HeaderWriterLogoutHandler(new ClearSiteDataHeaderWriter(SOURCE)))
          );
    }
}

ただし、ストレージクレンジングでは、1種類のストレージのみをクリアすると、アプリケーションの状態が破損する可能性があります。 したがって、不完全なクリアにより、ヘッダーは要求が安全である場合にのみ適用されます。

5. リクエストに応じてログアウト

同様に、 HttpServletRequest.logout()メソッドを使用してユーザーをログアウトできます。

まず、リクエストに応じて logout()を手動で呼び出すために必要な構成を追加しましょう。

@Configuration
public static class LogoutOnRequestConfiguration extends WebSecurityConfigurerAdapter {
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.antMatcher("/request/**")
            .authorizeRequests(authz -> authz.anyRequest()
                .permitAll())
            .logout(logout -> logout.logoutUrl("/request/logout")
                .addLogoutHandler((request, response, auth) -> {
                    try {
                        request.logout();
                    } catch (ServletException e) {
                        logger.error(e.getMessage());
                    }
                }));
    }
}

最後に、すべてが期待どおりに機能することを確認するためのテストケースを作成しましょう。

@Test
public void givenLoggedUserWhenUserLogoutOnRequestThenSessionCleared() throws Exception {

    this.mockMvc.perform(post("/request/logout").secure(true)
        .with(csrf()))
        .andExpect(status().is3xxRedirection())
        .andExpect(unauthenticated())
        .andReturn();
}

6. 結論

要約すると、Spring Securityには、認証シナリオを処理するための多くの組み込み機能があります。 これらの機能をプログラムで使用する方法を習得すると、常に便利です。

いつものように、これらの例のコードはGitHubから入手できます。