概要
・Spring Securityを使用してログイン機能を実装していることを前提とします。
・今回、私がカスタマイズした処理の内容は【ログイン成功時にその日時を最終ログイン日時としてDBに保存する】という処理です。
※初記事なので分かりにくい場合や間違えてる場合等があるかもしれませんのでご了承ください...
実行環境
・Eclipse(2024)
・Spring Boot 3.3.0
・Spring Security 6
手順
1.CustomAuthenticationSuccessHandlerクラスの作成
・AuthenticationSuccessHandlerインターフェースを実装したカスタムハンドラを作成します。
・ログイン成功時にユーザの最終ログイン日時を更新するロジックを実装します。
2.ユーザサービスの作成
・ユーザの最終ログイン日時を更新するためのメソッドを含むサービスクラスを作成します。
3.セキュリティ設定の更新
・カスタムハンドラをSpring Securityの設定に登録します。
4. Userエンティティの更新
1.CustomAuthenticationSuccessHandlerクラスの作成
まずAuthenticationSuccessHandler
を継承したカスタムハンドラクラスを作成します。
※このハンドラは、ログインが成功した時に呼び出されます。
import org.springframework.security.core.Authentication;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
import org.springframework.stereotype.Component;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.time.LocalDateTime;
@Component
public class CustomAuthenticationSuccessHandler implements AuthenticationSuccessHandler {
private UserService userService;
// コンストラクタでUserServiceをインジェクション
public CustomAuthenticationSuccessHandler(UserService userService) {
this.userService = userService;
}
@Override
public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {
// 認証されたユーザの名前を取得
String username = authentication.getName();
// 現在の日時を最終ログイン日時としてUserServiceに渡して更新
userService.updateLastLogin(username, LocalDateTime.now());
// ログイン成功後にリダイレクトするURL
response.sendRedirect("/home");
}
}
ポイント
・CustomAuthenticationSuccessHandler
はAuthenticationSuccessHandler
インターフェースを実装しています。
・onAuthenticationSuccess
メソッドはログイン成功時に呼び出され、ユーザの名前を取得し、現在の日時を最終ログイン日時として更新するためにUserService
を呼び出します。
2.ユーザサービスの作成
ユーザの最終ログイン日時を更新するためのメソッドを持つサービスクラスを作成します。
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.time.LocalDateTime;
@Service
public class UserService {
@Autowired
private UserRepository userRepository;
public void updateLastLogin(String username, LocalDateTime lastLogin) {
// ユーザ名でユーザを検索
User user = userRepository.findByUsername(username);
if (user != null) {
// ユーザが存在する場合、最終ログイン日時を設定
user.setLastLogin(lastLogin);
// ユーザ情報を保存
userRepository.save(user);
}
}
}
ポイント
・UserService
クラスは、UserRepository
を使ってユーザ情報を操作します(UserRepository
の記述は省略)。
・updateLastLogin
メソッドは、ユーザ名でユーザを検索し、最終ログイン日時を設定して保存します。
3.セキュリティ設定の更新
カスタムハンドラをSpring Securityの設定に登録します。
import org.springframework.beans.factory.annotation.Autowired;
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.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
import com.example.web.service.AccountDetailsService;
@Configuration
@EnableWebSecurity
public class SecurityConfig {
@Autowired
private AuthenticationSuccessHandler customAuthenticationSuccessHandler;
@Bean
public SecurityFilterChain securityFilterilterChain(HttpSecurity http) throws Exception{
http.formLogin(login -> login
.loginPage("/login").permitAll()
.usernameParameter("loginId")
.passwordParameter("password")
.defaultSuccessUrl("/", true)
.failureUrl("/login?error")
.successHandler(customAuthenticationSuccessHandler)) // 成功時のハンドラを指定
.authorizeHttpRequests(authz -> authz
.requestMatchers("/confirmation").permitAll()
.requestMatchers("/css/**").permitAll()
.requestMatchers("/js/**").permitAll()
.requestMatchers("/images/**").permitAll()
.anyRequest().authenticated())
.logout(logout -> logout
.logoutUrl("/logout"))
return http.build();
}
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder(); // パスワードのエンコーダーとしてBCryptを使用
}
}
ポイント
・.successHandler
メソッドでカスタムハンドラを設定します。
4. Userエンティティの更新
ユーザエンティティに最終ログイン日時のフィールドを追加します。
import javax.persistence.*;
import java.time.LocalDateTime;
@Entity
@Data
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String username;
private String password;
private LocalDateTime lastLogin; // 最終ログイン日時のフィールドを追加
}
ポイント
・User
エンティティにlastLogin
フィールドを追加します。
※ご自身のDBに合わせてEntity
は作成してください。