概要
ログアウト機能を追加する方法についてまとめた。
前提
以下の記事の続きとなる。
概要 認証成功/失敗時に呼び出されるハンドラを利用して、後続処理を制御する方法についてまとめた。 前提 以下の記事の続きとなる。
ログアウト仕様
Spring Securityでは以下の流れでログアウト処理を行う。

②ログアウトのURLにマッチングして、LogoutFilterの処理が動作する
③LogoutFilterはログアウトハンドラのリストを保持しており、順次ログアウト処理を呼び出す
※デフォルトでは実装クラスのSecurityContextLogoutHandlerが呼ばれ、認証情報のクリアやセッションの破棄が行われる
④すべてのログアウト処理が完了した後、LogoutSuccessHandlerを呼び出して画面遷移等を行う
※デフォルトでは実装クラスのSimpleUrlLogoutSuccessHandlerが呼ばれ、ログアウト遷移先へリダイレクトする
実装
ログアウト機能を実装する。
ログアウト機能
ログアウトに必要な情報を定義する。
SecurityConfig.java
package com.example.prototype.biz.security.config;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.MessageSource;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.dao.DaoAuthenticationProvider;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.provisioning.InMemoryUserDetailsManager;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
import com.example.prototype.biz.security.handler.LoginFailureHandler;
import com.example.prototype.biz.security.handler.LoginSuccessHandler;
@Configuration
@EnableWebSecurity
public class SecurityConfig {
@Autowired
private LoginSuccessHandler loginSuccessHandler;
@Autowired
private LoginFailureHandler loginFailureHandler;
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
@Bean
public UserDetailsService userDetailsService(PasswordEncoder encoder) {
UserDetails disabledUser = User.withUsername("user")
.password(encoder.encode("password"))
.roles("USER")
.build();
return new InMemoryUserDetailsManager(disabledUser);
}
@Bean
public DaoAuthenticationProvider authenticationProvider(MessageSource messageSource,
PasswordEncoder passwordEncoder) {
var provider = new DaoAuthenticationProvider();
provider.setUserDetailsService(userDetailsService(passwordEncoder));
provider.setPasswordEncoder(passwordEncoder);
provider.setMessageSource(messageSource);
return provider;
}
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http
// CSRF機能を無効
.csrf(csrf -> csrf.disable())
// 認可ポリシー定義
.authorizeHttpRequests(auth -> auth
// 認証不要のURL
.requestMatchers(
new AntPathRequestMatcher("/authentication"),
new AntPathRequestMatcher("/logout")
).permitAll()
.anyRequest().authenticated())
// ログイン機能定義
.formLogin(form -> form
.loginPage("/authentication")
.loginProcessingUrl("/authentication/process")
.usernameParameter("loginId")
.passwordParameter("pass")
.successHandler(loginSuccessHandler)
.failureHandler(loginFailureHandler))
// ログアウト機能定義
.logout(logout -> logout
.logoutRequestMatcher(new AntPathRequestMatcher("/logout"))
.logoutSuccessUrl("/authentication?logout=true")
);
return http.build();
}
}
new AntPathRequestMatcher(“/authentication”),
new AntPathRequestMatcher(“/logout“)
).permitAll()
認可ルールを設定する。
上記により、「/logout」へのリクエストが認証不要となる。
ログアウトに関するルールを構成するためのメソッド。
この設定により、SecurityFilterChainにLogoutFilterが組み込まれ、ログアウト処理が有効化される。
ログアウト対象となるURLを指定するためのメソッド。
ログイン成功後に呼ばれるSimpleUrlLogoutSuccessHandlerのリダイレクト先URLを指定するためのメソッド。
クエリパラメータ「logout=true」を送信している。
画面制御
ログアウト用フォーム部品とメッセージ表示制御を追加する。
home.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>トップページ画面</title>
</head>
<body>
<form action="${pageContext.request.contextPath}/logout" method="post">
<input type="submit" value="ログアウト" />
</form>
<h3>トップページ</h1>
<p>${message}</p>
</body>
</html>
ログアウト用フォームを定義する。
リクエストする際のHTTPメソッドはPOSTとなるので注意。
login.jsp
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<title>ログイン画面</title>
</head>
<body>
<h2>ログイン</h2>
<c:if test="${not empty param.logout}">
<p>ログアウトしました</p>
</c:if>
<c:if test="${not empty SPRING_SECURITY_LAST_EXCEPTION}">
<p style="color: red;">
<c:out value="${SPRING_SECURITY_LAST_EXCEPTION.message}" />
</p>
</c:if>
<form action="${pageContext.request.contextPath}/authentication/process" method="post">
<label for="loginId">ログインID:</label>
<input type="text" id="loginId" name="loginId" autofocus />
<br />
<label for="password">パスワード:</label>
<input type="password" id="pass" name="pass" />
<br />
<input type="submit" value="ログイン" />
</form>
<br>
</body>
</html>
上記の記載により、クエリパラメータの値を判定できる。
クエリパラメータ「logout=true」が送信されている場合、ログアウトメッセージを表示する。
まとめ
☑ HttpSecurity.logout(…) を定義することで、SecurityFilterChainにLogoutFilterが組み込まれてログアウト処理が有効になる
☑ LogoutFilterは登録されたログアウトハンドラを順次実行し、認証情報のクリアやセッション破棄などを行う
☑ ログアウトをリクエストする際にはPOST通信で行う
