Spring Securityについて理解する②（ユーザ名とパスワードを使用した認証）

## ユーザ名とパスワードを使用した認証
以下の設定をSecurityConfig.javaに記載するだけで「ユーザー名」と「パスワード」を使用した基本的な認証ロジックを実装できる。

>```SecurityConfig.java
>@Configuration
>@EnableWebSecurity
>public class SecurityConfig {
>
>	@Bean
>	public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
>		http
>			.authorizeHttpRequests((authorize) -> authorize
>				.anyRequest().authenticated()
>			)
>			.httpBasic(Customizer.withDefaults())
>			.formLogin(Customizer.withDefaults());
>
>		return http.build();
>	}
>
>	@Bean
>	public UserDetailsService userDetailsService() {
>		UserDetails userDetails = User.withDefaultPasswordEncoder()
>			.username("user")
>			.password("password")
>			.roles("USER")
>			.build();
>
>		return new InMemoryUserDetailsManager(userDetails);
>	}
>
>}
>```
>[Username/Password Authentication](https://docs.spring.io/spring-security_/reference/servlet/authentication/passwords/index.html)

## AuthenticationManager Bean

以下のようにAuthenticationManagerを`@Bean`アノテーションを付けて、Beanとして登録すると
>@Service または Spring MVC @Controller などのカスタム認証を可能
>[Username/Password Authentication](https://docs.spring.io/spring-security_/reference/servlet/authentication/passwords/index.html)

とできる。

- **AuthenticationManager**:
AuthenticationProviderに認証を委譲し、ユーザーが認証できるかどうかの判断を行う。
- **DaoAuthenticationProvider**:
実際の認証を行うクラスで、`UserDetailsService`や`PasswordEncoder`を使ってユーザー情報を取得し、パスワードを検証する。
- **UserDetailsService**:
ユーザー情報を提供する役割を担い、`AuthenticationProvider`がユーザー情報を取得するために使用する。
- **PasswordEncoder**:
パスワードを暗号化し、認証時にパスワードの検証を行う役割がある。

>``` SecurityConfig.java
>@Configuration
>@EnableWebSecurity
>public class SecurityConfig {
>
>	@Bean
>	public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
>		http
>			.authorizeHttpRequests((authorize) -> authorize
>				.requestMatchers("/login").permitAll()
>				.anyRequest().authenticated()
>			);
>
>		return http.build();
>	}
>
>	@Bean
>	public AuthenticationManager authenticationManager(
>			UserDetailsService userDetailsService,
>			PasswordEncoder passwordEncoder) {
>		DaoAuthenticationProvider authenticationProvider = new DaoAuthenticationProvider();
>		authenticationProvider.setUserDetailsService(userDetailsService);
>		authenticationProvider.setPasswordEncoder(passwordEncoder);
>
>		return new ProviderManager(authenticationProvider);
>	}
>
>	@Bean
>	public UserDetailsService userDetailsService() {
>		UserDetails userDetails = User.withDefaultPasswordEncoder()
>			.username("user")
>			.password("password")
>			.roles("USER")
>			.build();
>
>		return new InMemoryUserDetailsManager(userDetails);
>	}
>
>	@Bean
>	public PasswordEncoder passwordEncoder() {
>		return PasswordEncoderFactories.createDelegatingPasswordEncoder();
>	}
>
>}
>```
>[Username/Password Authentication](https://docs.spring.io/spring-security_/reference/servlet/authentication/passwords/index.html)

### 認証の流れ
認証の流れとしては以下となる。

```
@Bean
	public AuthenticationManager authenticationManager(
			UserDetailsService userDetailsService,
			PasswordEncoder passwordEncoder ①) {
		DaoAuthenticationProvider authenticationProvider = new DaoAuthenticationProvider();
		authenticationProvider.setUserDetailsService(userDetailsService); ②③
		authenticationProvider.setPasswordEncoder(passwordEncoder); ②③

		return new ProviderManager(authenticationProvider); ④
	}
```
①ユーザーがログインしようとすると、ユーザー名とパスワードが`AuthenticationManager`に渡される
②`AuthenticationManager`は、このリクエストを`DaoAuthenticationProvider`に渡す
③`DaoAuthenticationProvider`は、`UserDetailsService`を使ってユーザー情報を取得し、`PasswordEncoder`でパスワードを検証する
④認証が成功すれば、認証済みのAuthenticationオブジェクトを返し、失敗すれば例外を投げる

### 認証ロジックのカスタマイズ
また、以下の部分をカスタムすることで、様々な認証ロジックを実装することができる。
``` java
// 固定値での認証
@Bean
	public UserDetailsService userDetailsService() {
		UserDetails userDetails = User.withDefaultPasswordEncoder()
			.username("user")
			.password("password")
			.roles("USER")
			.build();

		return new InMemoryUserDetailsManager(userDetails);
	}
```

``` java
// カスタムでの認証
@Bean
	public UserDetailsService userDetailsService() {
		
// カスタムロジックを記述

		return new InMemoryUserDetailsManager(userDetails);
	}
```

## 参考
以下のSpring Securityの公式ドキュメントを参考にしました。
[Username/Password Authentication](https://docs.spring.io/spring-security_/reference/servlet/authentication/passwords/index.html)