본문 바로가기

개인 프로젝트

SecurityConfig 수정 전/후

 

강의를 통해 배운 코드 (https://www.youtube.com/watch?v=3Ff7UHGG3t8&list=PLJkjrxxiBSFCcOjy0AAVGNtIa08VLk1EJ&index=7&t=2s)

@Configuration
@EnableWebSecurity
public class SecurityConfig {

		//AuthenticationManager가 인자로 받을 AuthenticationConfiguraion 객체 생성자 주입
		private final AuthenticationConfiguration authenticationConfiguration;

    public SecurityConfig(AuthenticationConfiguration authenticationConfiguration) {

        this.authenticationConfiguration = authenticationConfiguration;
    }

		//AuthenticationManager Bean 등록
		@Bean
    public AuthenticationManager authenticationManager(AuthenticationConfiguration configuration) throws Exception {

        return configuration.getAuthenticationManager();
    }

    @Bean
    public BCryptPasswordEncoder bCryptPasswordEncoder() {

        return new BCryptPasswordEncoder();
    }

    @Bean
    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {


        http
                .csrf((auth) -> auth.disable());

        http
                .formLogin((auth) -> auth.disable());

        http
                .httpBasic((auth) -> auth.disable());

        http
                .authorizeHttpRequests((auth) -> auth
                        .requestMatchers("/login", "/", "/join").permitAll()
                        .anyRequest().authenticated());

				//필터 추가 LoginFilter()는 인자를 받음 (AuthenticationManager() 메소드에 authenticationConfiguration 객체를 넣어야 함) 따라서 등록 필요
        http
                .addFilterAt(new LoginFilter(authenticationManager(authenticationConfiguration)), UsernamePasswordAuthenticationFilter.class);

        http
                .sessionManagement((session) -> session
                        .sessionCreationPolicy(SessionCreationPolicy.STATELESS));

        return http.build();
    }
}

 

위 코드를 적용하여 POSTMAN을 통해 JSON으로 데이터를 POST 한 뒤........

 

Spring Security에서 사용자가 인증을 시도할 때, PasswordEncoder가 올바르게 설정되지 않아서 발생하는 

java.lang.IllegalArgumentException: There is no PasswordEncoder mapped for the id "null" 에러가 발생했다. 특히 PasswordEncoder가 "null"로 식별되는 경우는 암호를 인코딩하거나 비교하는 과정에서 문제가 발생했다는 의미로 PasswordEncoder를 제대로 설정해야 한다.

 

다음으로 Spring 컨텍스트에서 순환 참조가 발생할 때 나타나는  BeanCurrentlyInCreationException 에러가 발생했다. 순환 참조는 두 개 이상의 빈이 서로를 필요로 하여 초기화가 무한 루프에 빠질 때 발생한다. 

순환 참조 문제를 해결하기 위해 Spring Security 설정을 명확하게 분리해야 한다. 이를 위해 AuthenticationManagerBuilder 설정을 SecurityConfig 클래스 내부에서 한번만 설정하고 filterChain 메서드에서 이를 사용하도록 변경하였다.

 

수정한 코드...........

@Configuration
@EnableWebSecurity
public class SecurityConfig{

    private CustomUserDetailsService userDetailsService;

    public SecurityConfig(CustomUserDetailsService userDetailsService) {

        this.userDetailsService = userDetailsService;
    }


    @Bean
    public BCryptPasswordEncoder bCryptPasswordEncoder() {

        return new BCryptPasswordEncoder();
    }


    @Bean
    public AuthenticationManager authenticationManager(HttpSecurity http) throws Exception {

        AuthenticationManagerBuilder authenticationManagerBuilder = http.getSharedObject(AuthenticationManagerBuilder.class);

        authenticationManagerBuilder
                .userDetailsService(userDetailsService)
                .passwordEncoder(bCryptPasswordEncoder());

        return authenticationManagerBuilder.build();
    }


    @Bean
    public SecurityFilterChain filterChain(HttpSecurity http, AuthenticationManager authenticationManager) throws Exception {

        http
                .csrf((auth) -> auth.disable());

        http
                .formLogin((auth) -> auth.disable());

        http
                .httpBasic((auth) -> auth.disable());

        http
                .authorizeHttpRequests((auth) -> auth
                        .requestMatchers("/", "/login", "/join").permitAll()
                        .anyRequest().authenticated());

        http
                .addFilterAt(new LoginFilter(authenticationManager), UsernamePasswordAuthenticationFilter.class);

        http
                .sessionManagement((session) -> session
                        .sessionCreationPolicy(SessionCreationPolicy.STATELESS));

        return http.build();
    }

}

 

첫 번째 코드와 두 번째 코드의 차이점

 

1. AuthenticationManager 설정 방식

  • 첫 번째 코드는 AuthenticationConfiguration을 통해 AuthenticationManager를 설정했다. AuthenticationConfiguration은 Spring Boot가 자동으로 설정한 AuthenticationManager를 제공한다.
  • 두 번째 코드는 AuthenticationManager를 HttpSecurity와 함께 설정하여 AuthenticationBuilder를 사용한다. HttpSecurity에서 AuthenticationBuilder를 가져와서  userDetailsService와 passwordEncoder를 설정한 후
    build() 메서드를 사용해 AuthenticationManager를 반환한다.

2. 필터 체인 설정

  • 첫 번째 코드는 AuthenticationConfiguration을 통해 AuthenticationManager를 가져와 filterChain 에서 사용했다.
  • 두 번째 코드는 AuthenticationManager를 HttpSecurity와 함께 설정한 후 filterChain 메서드에 인자로 받아 사용했다.

 

두 번째 코드가 작동한 이유는?

일단 첫 번째 코드는 더 간단하지만 CustomUserDetailsService 설정이 누락되었기 때문에 제대로 작동하지 않았을 가능성이 있다.

반면 두 번째 코드는 AuthenticationManager를 직접 설정하여 CustomUserDetailsService와 BCryptPasswordEncoder를 올바르게 설정하여 순환 참조 문제를 방지할 수 있었다.

 

 

 

 

'개인 프로젝트' 카테고리의 다른 글

Refresh Token  (0) 2024.08.13
LoginFilter, JWTFilter, Spring Security 인증 과정  (0) 2024.08.07
JWT Token + Spring Security  (0) 2024.07.27
401 Unauthorized  (0) 2024.07.26
궁금 & 계속 까먹음..  (0) 2024.07.25