-
카테고리
-
세부 분야
백엔드
-
해결 여부
해결됨
AjaxSecurityConfig 에러에 관해 질문드립니다.
22.10.06 22:21 작성 조회수 700
0
AjaxSecurityConfig 제작 중 authenticationManager must be specified 오류가 발생합니다.
@Configuration
@Order(0)
public class AjaxSecurityConfig {
private AuthenticationConfiguration authenticationConfiguration;
@Autowired
private void setAjaxSecurityConfig(AuthenticationConfiguration authenticationConfiguration) {
this.authenticationConfiguration = authenticationConfiguration;
}
@Bean
public AuthenticationManager authenticationManager(AuthenticationConfiguration authenticationConfiguration) throws Exception {
return authenticationConfiguration.getAuthenticationManager();
}
@Bean
public AccessDeniedHandler ajaxAccessDeniedHandler() {
return new AjaxAccessDeniedHandler();
}
@Bean
public AuthenticationProvider ajaxAuthenticationProvider(){
return new AjaxAuthenticationProvider(passwordEncoder());
}
@Bean
public AjaxAuthenticationSuccessHandler ajaxAuthenticationSuccessHandler(){
return new AjaxAuthenticationSuccessHandler();
}
@Bean
public AjaxAuthenticationFailureHandler ajaxAuthenticationFailureHandler(){
return new AjaxAuthenticationFailureHandler();
}
@Bean
public PasswordEncoder passwordEncoder() {
return PasswordEncoderFactories.createDelegatingPasswordEncoder();
}
@Bean
public SecurityFilterChain FilterChain(HttpSecurity http) throws Exception {
AuthenticationManagerBuilder authenticationManagerBuilder = http.getSharedObject(AuthenticationManagerBuilder.class);
authenticationManagerBuilder.authenticationProvider(ajaxAuthenticationProvider());
http
.antMatcher("/api/**")
.authorizeRequests()
.antMatchers("/api/messages").hasRole("MANAGER")
.antMatchers("/api/login").permitAll()
.anyRequest().authenticated()
.and()
.exceptionHandling()
.authenticationEntryPoint(new AjaxLoginAuthenticationEntryPoint())
.accessDeniedHandler(ajaxAccessDeniedHandler());
// http.csrf().disable();
ajaxConfigurer(http);
return http.build();
}
private void ajaxConfigurer(HttpSecurity http) throws Exception {
http
.apply(new AjaxLoginConfigurer<>())
.successHandlerAjax(ajaxAuthenticationSuccessHandler())
.failureHandlerAjax(ajaxAuthenticationFailureHandler())
.loginPage("/api/login")
.loginProcessingUrl("/api/login")
.setAuthenticationManager(authenticationManager(authenticationConfiguration));
}
// @Bean
// public AjaxLoginProcessingFilter ajaxLoginProcessingFilter() throws Exception {
// AjaxLoginProcessingFilter ajaxLoginProcessingFilter = new AjaxLoginProcessingFilter();
// ajaxLoginProcessingFilter.setAuthenticationManager(authenticationManager(authenticationConfiguration));
// ajaxLoginProcessingFilter.setAuthenticationSuccessHandler(ajaxAuthenticationSuccessHandler());
// ajaxLoginProcessingFilter.setAuthenticationFailureHandler(ajaxAuthenticationFailureHandler());
// return ajaxLoginProcessingFilter;
// }
}
public final class AjaxLoginConfigurer<H extends HttpSecurityBuilder<H>> extends AbstractAuthenticationFilterConfigurer<H, AjaxLoginConfigurer<H>, AjaxLoginProcessingFilter> {
private AuthenticationSuccessHandler successHandler;
private AuthenticationFailureHandler failureHandler;
private AuthenticationManager authenticationManager;
public AjaxLoginConfigurer() {
super(new AjaxLoginProcessingFilter(), null);
}
@Override
public void init(H http) throws Exception {
super.init(http);
}
@Override
public void configure(H http) {
if(authenticationManager == null){
authenticationManager = http.getSharedObject(AuthenticationManager.class);
}
getAuthenticationFilter().setAuthenticationManager(authenticationManager);
getAuthenticationFilter().setAuthenticationSuccessHandler(successHandler);
getAuthenticationFilter().setAuthenticationFailureHandler(failureHandler);
SessionAuthenticationStrategy sessionAuthenticationStrategy = http
.getSharedObject(SessionAuthenticationStrategy.class);
if (sessionAuthenticationStrategy != null) {
getAuthenticationFilter().setSessionAuthenticationStrategy(sessionAuthenticationStrategy);
}
RememberMeServices rememberMeServices = http
.getSharedObject(RememberMeServices.class);
if (rememberMeServices != null) {
getAuthenticationFilter().setRememberMeServices(rememberMeServices);
}
http.setSharedObject(AjaxLoginProcessingFilter.class,getAuthenticationFilter());
http.addFilterBefore(getAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class);
}
@Override
public AjaxLoginConfigurer<H> loginPage(String loginPage) {
return super.loginPage(loginPage);
}
public AjaxLoginConfigurer<H> successHandlerAjax(AuthenticationSuccessHandler successHandler) {
this.successHandler = successHandler;
return this;
}
public AjaxLoginConfigurer<H> failureHandlerAjax(AuthenticationFailureHandler authenticationFailureHandler) {
this.failureHandler = authenticationFailureHandler;
return this;
}
public AjaxLoginConfigurer<H> setAuthenticationManager(AuthenticationManager authenticationManager) {
this.authenticationManager = authenticationManager;
return this;
}
@Override
protected RequestMatcher createLoginProcessingUrlMatcher(String loginProcessingUrl) {
return new AntPathRequestMatcher(loginProcessingUrl, "POST");
}
}
Intellij 에서 AjaxLoginConfigurer에서 setAuthenticationManager 메소드 쪽에 Return value of the method is never used 라고 하는 것을 보면 Manager의 return 값이 없는 것 같습니다.
@Bean
public AjaxLoginProcessingFilter ajaxLoginProcessingFilter() throws Exception {
AjaxLoginProcessingFilter ajaxLoginProcessingFilter = new AjaxLoginProcessingFilter();
ajaxLoginProcessingFilter.setAuthenticationManager(authenticationManager(authenticationConfiguration));
ajaxLoginProcessingFilter.setAuthenticationSuccessHandler(ajaxAuthenticationSuccessHandler());
ajaxLoginProcessingFilter.setAuthenticationFailureHandler(ajaxAuthenticationFailureHandler());
return ajaxLoginProcessingFilter;
}
에서는 정상적으로 authenticationManager가 등록이 되었습니다. 오류가 왜 일어나는지는 알 것 같지만, 해결 방법이 도저히 이해가 가지 않습니다. 아니면 전에 올린 ajaxAuthenticationProvider가 등록되지 않은 것이 문제인지 생각했지만. Filter로는 잘 되어서 그 문제는 아닐 거라 생각해 질문을 올립니다.
전체 코드는 Othkkartho/SpringSecurityLearn at ch4.7 (github.com) 입니다. 좋은 강의와 질문 대답 항상 감사합니다.
답변을 작성해보세요.
0
정수원
지식공유자2022.10.14
네
@Component
public class AjaxLoginProcessingFilter
위에서 @Component 를 제거해야 합니다
AjaxLoginProcessingFilter 를 빈으로 정의하게 되면 빈의 라이프 사이클에서
@Override
public void afterPropertiesSet() {
Assert.notNull(this.authenticationManager, "authenticationManager must be specified");
}
위 메소드가 먼저 호출이 되기 때문에 실제
private void ajaxConfigurer(HttpSecurity http) throws Exception {
http
.apply(new AjaxLoginConfigurer<>())
.successHandlerAjax(ajaxAuthenticationSuccessHandler())
.failureHandlerAjax(ajaxAuthenticationFailureHandler())
.loginPage("/api/login")
.loginProcessingUrl("/api/login")
.setAuthenticationManager(authenticationManager(authenticationConfiguration));
}
위이 메소드가 실행되지 못해서 AjaxLoginProcessingFilter 에서 필수값인 AuthenticationManager 를 저장하지 못하고 있습니다.
그리고 스프링 시큐리티에서 필터를 생성하고 등록할 때 대부분 빈으로 등록하지 않습니다.
public final class FormLoginConfigurer<H extends HttpSecurityBuilder<H>> extends
AbstractAuthenticationFilterConfigurer<H, FormLoginConfigurer<H>, UsernamePasswordAuthenticationFilter> {
/**
* Creates a new instance
* @see HttpSecurity#formLogin()
*/
public FormLoginConfigurer() {
super(new UsernamePasswordAuthenticationFilter(), null);
usernameParameter("username");
passwordParameter("password");
}
초기화 설정에서 폼인증을 담당하는 필터인 UsernamePasswordAuthenticationFilter 를 생성하고 있는데 보시면 빈이 아닌 일반 POJO 로 생성하는 것을 알 수 있습니다. 그래서 빈의 라이프 사이클을 타지 않도록 합니다.
new UsernamePasswordAuthenticationFilter()
결론은 AjaxLoginProcessingFilter 의 @Component 를 삭제하면 됩니다.
답변 1