22.10.05 22:02 작성
·
933
0
@Configuration
@Order(0)
public class AjaxSecurityConfig {
private AuthenticationConfiguration authenticationConfiguration;
@Autowired
private void setAjaxSecurityConfig(AuthenticationConfiguration authenticationConfiguration) {
this.authenticationConfiguration = authenticationConfiguration;
}
@Bean
public AuthenticationProvider ajaxAuthenticationProvider() {
return new AjaxAuthenticationProvider();
}
@Bean
public AuthenticationManager authenticationManager(AuthenticationConfiguration authenticationConfiguration) throws Exception {
return authenticationConfiguration.getAuthenticationManager();
}
@Bean
public SecurityFilterChain ajaxFilterChain(HttpSecurity http) throws Exception {
AuthenticationManagerBuilder authenticationManagerBuilder = http.getSharedObject(AuthenticationManagerBuilder.class);
authenticationManagerBuilder.authenticationProvider(ajaxAuthenticationProvider());
http
.antMatcher("/api/**")
.authorizeRequests()
.anyRequest().authenticated()
.and()
.addFilterBefore(ajaxLoginProcessingFilter(), UsernamePasswordAuthenticationFilter.class);
http.csrf().disable();
return http.build();
}
@Bean
public AjaxLoginProcessingFilter ajaxLoginProcessingFilter() throws Exception {
AjaxLoginProcessingFilter ajaxLoginProcessingFilter = new AjaxLoginProcessingFilter();
ajaxLoginProcessingFilter.setAuthenticationManager(authenticationManager(authenticationConfiguration));
return ajaxLoginProcessingFilter;
}
}
AjaxSecurityConfig.java
AjaxAuthenticationProvider.java
@Component
public class AjaxAuthenticationProvider implements AuthenticationProvider {
private UserDetailsService userDetailsService;
private PasswordEncoder passwordEncoder;
@Autowired
private void setAjaxAuthenticationProvider(UserDetailsService userDetailsService, PasswordEncoder passwordEncoder) {
this.userDetailsService = userDetailsService;
this.passwordEncoder = passwordEncoder;
}
@Override
@Transactional
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
AccountContext accountContext = FormAuthenticationProvider.authenticationIf(authentication, userDetailsService, passwordEncoder);
return new AjaxAuthenticationToken(accountContext.getAccount(), null, accountContext.getAuthorities());
}
@Override
public boolean supports(Class<?> authentication) {
return authentication.equals(AjaxAuthenticationToken.class);
}
}
설정을 모두 완료하고 확인해보니 Filter는 정상적으로 등록이 되고, ProviderManager에 넘기는 것 까지는 진행이 됩니다. 그런대 ProviderManager에 BreakPoint를 걸고 확인해 보니 DaoAuthenticationProvider만 providers에 등록이 되어있습니다. 그래서 Form 방식을 확인해 보니 Form은 정상작동 하는 것을 확인했습니다. 혹시 자세한 코드가 필요하시다면 아래 링크의 브런치 ch4.3입니다. 항상 모든 질문에 최선을 다해 답변해 주시니 감사합니다.
추가 사항으로 SecurityConfig에 넣어서 돌렸더니 Provider가 정상적으로 추가되는 것을 확인했습니다. 또한 오류는 인식하고, AjaxAuthenticationFailureHandler는 또 호출을 합니다. 점점 뭐가 문제인지 잘 모르겠습니다.
답변 2
2
2022. 10. 07. 18:18
네
일단 코드는 다음과 같이 수정되어야 합니다.
@Bean
public AuthenticationManager authenticationManager(AuthenticationConfiguration authenticationConfiguration) throws Exception {
ProviderManager authenticationManager = (ProviderManager)authenticationConfiguration.getAuthenticationManager();
authenticationManager.getProviders().add(ajaxAuthenticationProvider());
return authenticationManager;
}
@Bean
public SecurityFilterChain FilterChain(HttpSecurity http) throws Exception {
/*AuthenticationManagerBuilder authenticationManagerBuilder = http.getSharedObject(AuthenticationManagerBuilder.class);
authenticationManagerBuilder.authenticationProvider(ajaxAuthenticationProvider());*/
사실 이 부분은 스프링 시큐리티의 내부 구조를 정확하게 이해하지 못하면 혼돈하게 되는데요..
AuthenticationManager 는 초기화 때 생성되어 기본적으로 DaoAuthenticationProvider 와 같은 객체를 가지고 있습니다.
그리고 UsernamePasswordAuthenticationFilter 와 같은 클래스에서 참조하고 있습니다.
그렇다면 ajaxAuthenticationProvider 도 초기화때 생성된 AuthenticationManager 에서 추가해 주어야 합니다.
바로
AuthenticationManagerBuilder authenticationManagerBuilder = http.getSharedObject(AuthenticationManagerBuilder.class);
authenticationManagerBuilder.authenticationProvider(ajaxAuthenticationProvider());
위 코드가 초기화 때 생성된 AuthenticationManager 입니다.
그런데 실제 AjaxLoginProcessingFilter 를 생성하는 코드를 보시면
@Bean
public AjaxLoginProcessingFilter ajaxLoginProcessingFilter() throws Exception {
AjaxLoginProcessingFilter ajaxLoginProcessingFilter = new AjaxLoginProcessingFilter();
ajaxLoginProcessingFilter.setAuthenticationManager(authenticationManager(authenticationConfiguration));
return ajaxLoginProcessingFilter;
}
초기화 때 생성된 동일한 AuthenticationManager 가 아닌 다른 AuthenticationManager 를 참조하고 있습니다.
즉 authenticationConfiguration.getAuthenticationManager(); 에서 참조하고 있는 AuthenticationManager 와 authenticationManagerBuilder.authenticationProvider(ajaxAuthenticationProvider()); 를 통해 참조되는 AuthenticationManager 는 동일한 객체가 아닙니다.
그렇기 때문에 AjaxLoginProcessingFilter 에서 참조하고 있는 AuthenticationManager 에 ajaxAuthenticationProvider 를 추가해 주어야 정상동작하게 됩니다.
위 코드로 수정한 후에 디버깅해 보시면 AuthenticationManager 가 서로 다른 두개의 객체가 생성되어 있음을 알게 됩니다.
조금 어려운 개념이긴 하지만 ProviderManager 의 생성과정을 이해하시는게 중요합니다
0
2022. 10. 07. 18:45
아 감사합니다. 공부 하면 할수록 공부할께 더 많아지는 마법이 있는거 같네요.