SpringSecurity6 メモリベースのユーザー認証ソースコード解析 

## 1. Security のコア概念

![image-20250218133500811.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3809422/6f48a7f7-918f-48a2-8d14-9125efd7e950.png)
Spring Security の本質は **フィルターチェーン（Filter Chain）** であり、内部には異なる機能を提供する複数のフィルターが含まれています。基本的なアプリケーションにおいて、フィルターチェーンの主要なフィルターは以下のとおりです：

- **UsernamePasswordAuthenticationFilter**：ユーザー名とパスワードに基づくログインリクエストを処理し、ユーザー認証を担当する。
- **ExceptionTranslationFilter**：フィルターチェーン内で発生した `AccessDeniedException` や `AuthenticationException` をキャッチし、適切に処理する。
- **FilterSecurityInterceptor**：アクセス制御の決定を担当し、ユーザーが保護されたリソースにアクセスする権限を持っているかどうかを検証する。

Spring Security のフィルターチェーンの具体的な構成や実行順序は、デバッグモードで確認できます。

![img](https://img2024.cnblogs.com/blog/3533151/202410/3533151-20241010000144347-1049514666.png)

## 2. Security 認証プロセス

### 2.1 Security 設定クラス

Spring Security 5.7 以降では、`WebSecurityConfigurerAdapter` を継承するのではなく、`SecurityFilterChain` を使用してセキュリティポリシーを設定することが推奨されています。

```
@Configuration
public class WebSecurityConfig {

    @Bean
    public UserDetailsService userDetailsService() {
        // ユーザーオブジェクトを作成
        UserDetails user = User.withUsername("Tanaka")
                .password("{noop}111111")  // `{noop}` は暗号化なし
                .roles("USER")
                .build();

        // InMemoryUserDetailsManager を作成し、ユーザー情報を登録
        InMemoryUserDetailsManager userDetailsManager = new InMemoryUserDetailsManager();
        userDetailsManager.createUser(user);

        // UserDetailsService を返し、Spring Security に管理させる
        return userDetailsManager;
    }
}
```
`UserDetailService` インターフェースに入ると、重要なメソッドがあり、次に使用されます
![image-20250218091145800.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3809422/d4f04355-0d44-467d-8cd1-7d7d27ea0dde.png)


### 2.2 認証プロセス（Authentication）

#### 1. ユーザーがログインリクエストを送信

ユーザーがフォームログインを行う際、Spring Security に組み込まれている `UsernamePasswordAuthenticationFilter` フィルターが `POST /login` リクエストをキャッチし、`attemptAuthentication` メソッドを呼び出します。

![image-20250218091344283.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3809422/a0ab5c5b-d892-493f-9913-41e25b4d6cba.png)
次に `AbstractAuthenticationProcessingFilter` メソッドに進みます。
![image-20250218091528234.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3809422/22b93031-9a99-4d61-8148-aeb13317e082.png)
このフィルターが実行され、`attemptAuthentication` メソッドに入ります。

#### 2. 認証オブジェクトの作成

`UsernamePasswordAuthenticationFilter` はリクエストパラメータを解析し、`UsernamePasswordAuthenticationToken` を使用してユーザーの認証情報（ユーザー名とパスワード）をカプセル化します。

```
Authentication authentication = new UsernamePasswordAuthenticationToken(username, password);
```

![image-20250218091712197.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3809422/8b44da64-2003-4385-a845-6d8668009277.png)

#### 3. `AuthenticationManager` による認証処理

`AuthenticationManager`（デフォルト実装は `ProviderManager`）は `Authentication` オブジェクトを受け取り、`AuthenticationProvider` に委託して認証を行います。

```
Authentication authenticationResult = authenticationManager.authenticate(authentication);
```

![image-20250218091750954.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3809422/2bef3d07-6088-4e8f-a9a6-e069c65a67c0.png)


#### 4. `AuthenticationProvider` による認証処理

`ProviderManager` は内部で複数の `AuthenticationProvider` を管理しており、デフォルトでは `DaoAuthenticationProvider` が使用されます。

![image-20250218093104764.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3809422/3acca6fa-c768-48a8-a744-0396f4037857.png)

![image-20250218093248946.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3809422/fca37c0a-b5dc-4923-bb24-89566ae21190.png)

![image-20250218093622031.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3809422/4ebcfe53-71ea-408a-8a78-c83dc92dc9bc.png)


#### 5. ユーザー情報のロード（UserDetailsService）

`DaoAuthenticationProvider` は `UserDetailsService#loadUserByUsername()` メソッドを呼び出し、メモリやデータベースからユーザー情報をロードします。

```
@Override
protected UserDetails retrieveUser(String username, UsernamePasswordAuthenticationToken authentication) {
    return this.userDetailsService.loadUserByUsername(username);
}
```

![image-20250218093414008.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3809422/8f2a32e1-c77c-4f23-be6b-0c5e060b1978.png)

![image-20250218093714270.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3809422/6c56a2bb-527f-4756-9fdd-e297cf76bb41.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3809422/45e70543-9b25-4086-814c-6b8d67d6eaba.png)

![image-20250218094415937.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3809422/77dbe476-ff2d-4321-9cca-e4f056f43c2f.png)


#### 6. パスワードの検証

`DaoAuthenticationProvider` は `PasswordEncoder#matches()` メソッドを使用して、入力されたパスワードと保存されているパスワードを比較します。

```
@Override
protected void additionalAuthenticationChecks(UserDetails userDetails, UsernamePasswordAuthenticationToken authentication) {
    if (!passwordEncoder.matches(authentication.getCredentials().toString(), userDetails.getPassword())) {
        throw new BadCredentialsException("Invalid password");
    }
}
```

![image-20250218094548117.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3809422/3f3c2acb-c829-455f-9c3a-240874b17f90.png)

![image-20250218094656562.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3809422/a5ab941f-b754-4228-92dd-0d484e1b9ca3.png)


#### 7. 認証結果の処理

- **認証成功**：

  - `Authentication` オブジェクトが作成され、`SecurityContextHolder` に設定される。
  - `AuthenticationSuccessHandler` がトリガーされ、（デフォルトでは元のアクセスページまたはホームページにリダイレクト）。

  **認証失敗**：

  - `AuthenticationFailureHandler` がトリガーされ、認証失敗のレスポンスを返す。

```
if (authentication.isAuthenticated()) {
    SecurityContextHolder.getContext().setAuthentication(authentication);
}
```



![image-20250218094744688.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3809422/e7a05825-d6a8-44fc-b793-ea17060e77e6.png)


![image-20250218095243524.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3809422/4157ae42-3c1f-4399-a2cb-d75157cb5631.png)


![image-20250218100454943.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3809422/b37f5777-c681-4c52-9079-d2550345a114.png)


![image-20250218100510014.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3809422/d5a3c39b-b4df-4049-aad9-62f024f533b7.png)

![image-20250218100807659.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3809422/db58b078-6bdd-4c81-8480-66bb7e0d333c.png)

## 3. 各オブジェクト間の関係

![file_1739858115906_453.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3809422/72a9bb94-7cbb-4d34-814c-f3e9fbf8b578.png)