概要
ユーザー向け画面と管理画面の2つを作成したいケースがあると思います。
その際に、SecurityFilterChainの書き方で迷ったので備忘します。
SpringBoot3(SpringSecurity6)の記事が少なかった点と、
SpringBoot2の時と比べて差異があったため、記事にしました。
まとめ
-
SecurityFilterChain
でsecurityMatcher
を利用する -
Order
の優先順位に注意する。
サンプルコード
ユーザー向け画面のSecurityFilterChain。
public class UserSecurityConfig {
@Bean
@Order(1)
public SecurityFilterChain userSecurityFilterChain(HttpSecurity http) throws Exception {
// URL認可
http.securityMatcher("/user/**").authorizeHttpRequests((request) -> request
// 常に許可
.requestMatchers("/user/login").permitAll()
.requestMatchers("/user/certification").permitAll()
// ユーザー権限のみ許可
.requestMatchers("/user/home").hasAuthority("USER")
)
// ログイン
.formLogin(formLogin -> formLogin
.loginPage("/user/login")
.loginProcessingUrl("/user/certification")
.defaultSuccessUrl("/user/home")
.failureUrl("/user/login?error")
)
// ログアウト
.logout(logout -> logout
.logoutUrl("/user/logout")
.logoutSuccessUrl("/user/login?logout=success")
.deleteCookies("JSESSIONID") // ログアウト後にCookie'JSESSIONID'を削除
.invalidateHttpSession(true) // ログアウト後にセッション無効化
)
return http.build();
}
}
管理者向け画面のSecurityFilterChain。
Order
の値を変更して優先度を整理する。
public class AdminSecurityConfig {
@Bean
@Order(2)
public SecurityFilterChain adminSecurityFilterChain(HttpSecurity http) throws Exception {
// URL認可
http.securityMatcher("/admin/**").authorizeHttpRequests((request) -> request
// 常に許可
.requestMatchers("/admin/login").permitAll()
.requestMatchers("/admin/certification").permitAll()
// 管理者権限のみ許可
.requestMatchers("/admin/home").hasAuthority("ADMIN")
)
// ログイン
.formLogin(formLogin -> formLogin
.loginPage("/admin/login")
.loginProcessingUrl("/admin/certification")
.defaultSuccessUrl("/admin/home")
.failureUrl("/admin/login?error")
)
// ログアウト
.logout(logout -> logout
.logoutUrl("/admin/logout")
.logoutSuccessUrl("/admin/login?logout=success")
.deleteCookies("JSESSIONID") // ログアウト後にCookie'JSESSIONID'を削除
.invalidateHttpSession(true) // ログアウト後にセッション無効化
)
return http.build();
}
}
ロールを付与するクラスを用意する。
@Component
public class AuthenticationSuccessEventListener {
@EventListener
public void onInteractiveAuthenticationSuccessEvent(InteractiveAuthenticationSuccessEvent event) {
// 認証情報を取得
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
UserDetails principal = (UserDetails) authentication.getPrincipal();
Object credentials = authentication.getCredentials();
// 権限情報を設定
List<SimpleGrantedAuthority> authorities = new ArrayList<>();
HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.currentRequestAttributes()).getRequest();
if (request.getServletPath().startsWith("/user")) {
authorities.add(new SimpleGrantedAuthority("USER"));
} else if (request.getServletPath().startsWith("/admin")) {
authorities.add(new SimpleGrantedAuthority("ADMIN"));
}
// 認証情報を再設定
Authentication newAuthentication = new UsernamePasswordAuthenticationToken(
principal,
credentials,
authorities);
SecurityContextHolder.getContext().setAuthentication(newAuthentication);
}
}