ログイン認証 DB接続編

# はじめに

SpringSecurityを使用したログイン認証については、framework内で処理が行われているため、少々わかりにくいことがあるかと思います。認証プロセスを理解することで認証周りの開発も躓くことなく進められると思いますので、今回はDB接続編について確認していきます。

認証におけるプロセスについては以下に記載しておりますので参照してください。
[SpringSecurityを使用した認証プロセス](https://qiita.com/atsuuun/items/6f8de21022f125031cf8#springsecurity%E3%82%92%E4%BD%BF%E7%94%A8%E3%81%97%E3%81%9F%E8%AA%8D%E8%A8%BC%E3%83%97%E3%83%AD%E3%82%BB%E3%82%B9)

# DB接続を使用したパスワード認証についてのサンプルコード

UserDetailsServiceをDB接続版として実装します。
loadUserByNameをDBに保持しているユーザ情報から取得するようにします。

``` CustomUserDetailsService.java
public class CustomUserDetailsService implements UserDetailsService {

    private final UserRepository userRepository;

    public CustomUserDetailsService(UserRepository userRepository) {
        this.userRepository = userRepository;
    }

    /**
     * 指定されたユーザー名に基づいてユーザーの詳細情報をロードします。
     * 
     * @param username ユーザー名
     * @return UserDetailsインスタンス
     * @throws UsernameNotFoundException ユーザーが見つからない場合にスローされます
     */
    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        // ユーザー名に基づいてユーザーを検索
        User user = userRepository.findByUsername(username);
        if (user == null) {
            // ユーザーが見つからない場合は例外をスロー
            throw new UsernameNotFoundException("User not found");
        }
        // ユーザーの詳細情報を返す
        return org.springframework.security.core.userdetails.User.withUsername(user.getUsername())
                .password(user.getPassword()).roles(user.getRole()).build();
    }
}
```

SecurityConfigの実装となります。
* configure 認証用プロバイダをauthenticationProviderに設定します。authenticationProviderに設定変更することでDBでのアクセス認証に変更できます。
* passwordEncoder 認証時のパスワードを変更

``` SecurityCongig.java
public class SecurityConfig {

    private final UserDetailsService userDetailsService;

    public SecurityConfig(UserDetailsService userDetailsService) {
        this.userDetailsService = userDetailsService;
    }


    @Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
        http.authorizeHttpRequests(authorizeRequests -> authorizeRequests
                .requestMatchers("/css/**", "/index").permitAll() // /css/** と /index へのアクセスを全て許可
                .requestMatchers("/user/**").hasRole("USER") // /user/** へのアクセスを USER ロールを持つユーザーに限定
                .requestMatchers("/admin/**").hasRole("ADMIN") // /admin/** へのアクセスを ADMIN
                                                               // ロールを持つユーザーに限定
                .anyRequest().authenticated() // その他の全てのリクエストは認証を要求
        ).formLogin(formLogin -> formLogin.loginPage("/login").permitAll() // ログインページへのアクセスを全て許可
        ).logout(logout -> logout.logoutUrl("/logout").permitAll() // ログアウトURLへのアクセスを全て許可
        );
        return http.build();
    }

    /**
     * パスワードエンコーダーを構成します。
     * 
     * @return BCryptPasswordEncoderインスタンス
     */
    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }

    /**
     * カスタムUserDetailsServiceとPasswordEncoderを使用してDaoAuthenticationProviderを構成します。
     * 
     * @return 構成されたDaoAuthenticationProviderインスタンス
     */
    @Bean
    public DaoAuthenticationProvider authenticationProvider() {
        DaoAuthenticationProvider authProvider = new DaoAuthenticationProvider();
        authProvider.setUserDetailsService(userDetailsService);
        authProvider.setPasswordEncoder(passwordEncoder());
        return authProvider;
    }

    public void configure(AuthenticationManagerBuilder auth) {
        auth.authenticationProvider(authenticationProvider());
    }
}
```

# まとめ
SpringSecurityにおいてDB接続にてパスワード認証を行う場合のカスタム方法について解説しました。
サンプルソースについてはGITに公開しているので、参考にしてみてください。
[springboot-login DB接続版](https://github.com/yana141421356/springboot-login/tree/mysqldb)