【Spring Security】WebSecurityConfigurerAdapterからの脱却

# はじめに
Spring bootでログイン機能を実装する方法を解説している記事を探した際、現在では非推奨になっているやり方でログイン機能を実装している記事ばかりが出てきて苦労したので、備忘録として書き残しておきます。

# WebSecurityConfigurerAdapterは現在非推奨に
Spring bootのログイン機能の実装方法を検索すると、多くはこれを継承してうんたらかんたらみたいな記事が出てくると思います。ですが、これは現在非推奨になっています。使っても深刻なエラーになったりはしませんが、非推奨にされたものを使い続けるのは将来のことを考えるとよくありません。

# Configクラスの書き方
ソースコードは以下のようになります。WebSecurityConfigurerAdapterを継承していないことに注目してください。これが現時点での新しい書き方です。URLなどは自身のWebサイトで使うものに応じて置き換えてください。

```java
package dev.itboot.todo.config;


import org.springframework.boot.autoconfigure.security.servlet.PathRequest;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration;
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.util.matcher.AntPathRequestMatcher;

import dev.itboot.todo.util.Role;
import lombok.RequiredArgsConstructor;

@RequiredArgsConstructor
@Configuration
@EnableWebSecurity
public class SecurityConfig {
	
	@Bean
	protected PasswordEncoder passwordEncoder() {
		//パスワードの暗号化
		return new BCryptPasswordEncoder();
	}

	@Bean
	protected SecurityFilterChain filterChain(HttpSecurity http) throws Exception{
		http
		.authorizeHttpRequests(authz -> authz
				//セキュリティ設定を無視するパスを指定する
				.requestMatchers(PathRequest.toStaticResources().atCommonLocations()).permitAll() //cssなどはログインなしでもアクセス可
				.mvcMatchers("/register", "/login").permitAll()
				.mvcMatchers("/admin/**").hasRole(Role.ADMIN.name())
				.anyRequest().authenticated()
		).formLogin(login -> login
				.loginProcessingUrl("/login")
				//ログイン時のURLを指定
				.loginPage("/login")
				//認証後にリダイレクトする場所を指定
				.defaultSuccessUrl("/")
				//ログイン失敗時のリダイレクト先
				.failureUrl("/login?error")
				.permitAll())
		.logout(logout -> logout
				.logoutRequestMatcher(new AntPathRequestMatcher("/logout")))
		//ブラウザを閉じて再度開いた場合でも「ログインしたままに」
		.rememberMe();
		
		return http.build();		
	}
	
	@Bean
	protected AuthenticationManager authenticationManager(AuthenticationConfiguration auth) throws Exception {
		return auth.getAuthenticationManager();
	}
}
```

ちなみに途中で使っているRoleというのは自分で作ったものです。これを使って、管理者だけがはこのページにアクセスできるみたいな機能が実現できます。

```java
public enum Role {
    ADMIN, USER
}
```

# おまけ
本番環境で残してちゃだめですが、テストとかの際に役立つものです。

- インメモリ認証の書き方

```java
@Bean
public InMemoryUserDetailsManager userDetailsService(){
    UserDetails user = User.builder()
        .username("user")
        .password(passwordEncoder().encode("password"))
        .authorities("ROLE_USER")
        .build();
    return new InMemoryUserDetailsManager(user);
}
```

- h2-consoleのアクセス許可
    - mvcMathchersとか書かれているところに、以下の記述を追加

```java
.antMatchers("/h2-console/**").permitAll()
```

次にreturnの直前に以下の記述を追加

```java
http.headers().frameOptions().disable();
http.csrf().ignoringAntMatchers("/h2-console/**");
```