6

이 문제는 여러 블로그 게시물 및 SO 질문에서 비교적 잘 논의됩니다. 그럼에도 불구하고, 나는 자바 구성에 대한 문제를 구체적으로 다루는 것을 찾을 수 없었다. 디버그 XML 태그 (https://jira.springsource.org/browse/SEC-1885)를 제거하여 문제가 해결 될 수 있음을 알리는 게시물을 발견했기 때문에 Java 구성 파일에서 잘못된 작업을하고있는 것으로 의심됩니다.Spring Security 3.2 : @Autowire는 Spring MVC 애플리케이션에서 자바 설정과 커스텀 AuthenticationProvider와 동작하지 않습니까?

스프링 보안의 3.2.0.RELEASE와 스프링 프레임 워크의 3.2.6.RELEASE를 사용하고 있습니다. 스프링 보안/mvc 설정과 커스텀 AuthenticationProvider에서 사용되는 메인 파일들 아래.

WebConfig :

@Configuration 
@EnableWebMvc 
@ComponentScan(basePackages = {"com.mypackage"}) 
@ImportResource({ "classpath:/spring-data.xml", "classpath:/trace-context.xml" }) 
@EnableTransactionManagement 
public class WebConfig extends WebMvcConfigurerAdapter { 

    @Override 
    public void addViewControllers(ViewControllerRegistry registry) { 
     registry.addViewController("/login").setViewName("login"); 
    } 

    @Bean 
    public StandardServletMultipartResolver multipartResolver() { 
     return new StandardServletMultipartResolver(); 
    } 

    @Bean(destroyMethod = "shutdown") 
    public GraphDatabaseService graphDatabaseService() { 
     return new GraphDatabaseFactory().newEmbeddedDatabase("target/temp.db"); 
    } 

    @Bean 
    public RepositoryInitializer repositoryInitializer() { 
     return new RepositoryInitializer(); 
    } 

    @Override 
    public void addResourceHandlers(ResourceHandlerRegistry registry) { 
     registry.addResourceHandler("/resources/**").addResourceLocations("/resources/"); 
    } 

    @Override 
    public void addInterceptors(InterceptorRegistry registry) { 
     LocaleChangeInterceptor localeChangeInterceptor = new   LocaleChangeInterceptor(); 
     localeChangeInterceptor.setParamName("lang"); 
     registry.addInterceptor(localeChangeInterceptor); 
    } 

    @Bean 
    public LocaleResolver localeResolver() { 
     CookieLocaleResolver cookieLocaleResolver = new CookieLocaleResolver(); 
     cookieLocaleResolver.setDefaultLocale(StringUtils.parseLocaleString("en")); 
     return cookieLocaleResolver; 
    } 

    @Bean 
    public ViewResolver viewResolver() { 
     InternalResourceViewResolver viewResolver = new InternalResourceViewResolver(); 
     viewResolver.setViewClass(JstlView.class); 
     viewResolver.setPrefix("/WEB-INF/views/"); 
     viewResolver.setSuffix(".jsp"); 
     return viewResolver; 
    } 

    @Bean 
    public MessageSource messageSource() { 
     ReloadableResourceBundleMessageSource messageSource = new ReloadableResourceBundleMessageSource(); 
     messageSource.setBasenames("classpath:messages/messages", "classpath:messages/validation"); 
     // if true, the key of the message will be displayed if the key is not 
     // found, instead of throwing a NoSuchMessageException 
     messageSource.setUseCodeAsDefaultMessage(true); 
     messageSource.setDefaultEncoding("UTF-8"); 
     // # -1 : never reload, 0 always reload 
     messageSource.setCacheSeconds(0); 
     return messageSource; 
    } 
} 

WebInitializer :

public class WebInitializer extends AbstractAnnotationConfigDispatcherServletInitializer { 

    @Override 
    protected Class<?>[] getRootConfigClasses() { 
     return new Class[] { WebSecurityConfig.class }; 
    } 

    @Override 
    protected Class<?>[] getServletConfigClasses() { 
     return new Class<?>[] { WebConfig.class}; 
    } 

    @Override 
    protected String[] getServletMappings() { 
     return new String[] { "/" }; 
    } 

    @Override 
    protected Filter[] getServletFilters() { 
     CharacterEncodingFilter characterEncodingFilter = new CharacterEncodingFilter(); 
     characterEncodingFilter.setEncoding("UTF-8"); 
     return new Filter[] { characterEncodingFilter, new SiteMeshFilter()}; 
    } 

    @Override 
    public void onStartup(ServletContext servletContext) throws ServletException { 
     super.onStartup(servletContext); 
     //servletContext.addListener(new HttpSessionEventPublisher()); 
    } 
} 

WebSecurityConfig :

@Configuration 
@EnableWebSecurity 
@Order(1) 
public class WebSecurityConfig extends WebSecurityConfigurerAdapter { 

    @Override 
    protected void configure(HttpSecurity http) throws Exception { 
     http 
      .authorizeRequests().anyRequest().permitAll(); 
     // .antMatchers("/", "/login").permitAll() 
     // .anyRequest().authenticated(); 
     http 
      .formLogin() 
       .defaultSuccessUrl("/hello") 
       .loginPage("/login") 
       .permitAll() 
       .and() 
      .logout() 
       .logoutUrl("/logout") 
       .permitAll(); 
     http  
      .sessionManagement() 
      .maximumSessions(1) 
      .maxSessionsPreventsLogin(true); 

    }  

    @Override 
    public void configure(WebSecurity web) throws Exception { 
     web 
      .ignoring() 
      .antMatchers("/resources/**"); 
    } 

    @Override 
    protected void configure(AuthenticationManagerBuilder authManagerBuilder) throws Exception { 
     authManagerBuilder.authenticationProvider(new ApplicationAuthenticationProvider()); 
    } 
} 

WebSecurityInitializer :

public class WebSecurityInitializer extends AbstractSecurityWebApplicationInitializer { 

} 

의 AuthenticationProvider :

@Component(value = "authenticationProvider") 
public class ApplicationAuthenticationProvider implements AuthenticationProvider { 

    @Autowired 
    public UserService userService; 

    public ApplicationAuthenticationProvider() {} 

    @Override 
    public Authentication authenticate(Authentication authentication) throws AuthenticationException { 
     String username = authentication.getName(); 
     String password = (String) authentication.getCredentials(); 

     User user = userService.loadUserByUsername(username); 

     if (user == null) { 
      throw new BadCredentialsException("Username not found."); 
     } 

     if (!password.equals(user.getPassword())) { 
      throw new BadCredentialsException("Wrong password."); 
     } 

     Collection<? extends GrantedAuthority> authorities = user.getAuthorities(); 

     return new UsernamePasswordAuthenticationToken(username, password, authorities); 
    } 

    @Override 
    public boolean supports(Class<?> arg0) { 
     return true; 
    } 
} 

는 UserService : 그것은 (응용 프로그램 초기화 중)의 애플리케이션 컨텍스트를 구축하는 동안

@Service 
public class UserService implements UserDetailsService { 

    @Autowired 
    private UserRepository userRepository; 


    @Override 
    public User loadUserByUsername(String username) throws UsernameNotFoundException { 
     return userRepository.findByUsername(username); 
    } 
} 

봄이 예외를 던지고 것은 :

[ERROR] [main 11:53:37] (FrameworkServlet.java:initServletBean:467) Context  initialization failed 
org.springframework.beans.factory.BeanCreationException: Error creating bean with name   'authenticationProvider': Injection of autowired dependencies failed; nested exception is  org.springframework.beans.factory.BeanCreationException: Could not autowire field: public  com.evidencefactory.service.UserService  com.evidencefactory.security.ApplicationAuthenticationProvider.userService; nested  exception is java.lang.IllegalArgumentException: Can not set  com.evidencefactory.service.UserService field  com.evidencefactory.security.ApplicationAuthenticationProvider.userService to  sun.proxy.$Proxy71 

이해가 안 왜 그런 일이 벌어 지지만, UserDetailsService 인터페이스 구현을에서 제거하면210 클래스이면 응용 프로그램이 성공적으로 시작됩니다. 그러나 ApplicationAuthenticationProvider이 Spring에 의해 호출 될 때 UserService은 autowired되지 않으며 응용 프로그램은 NullPointerException을 발생시킵니다.

java.lang.NullPointerException 
at com.evidencefactory.security.ApplicationAuthenticationProvider.authenticate(ApplicationAuthenticationProvider.java:33) 
+0

'UserService' 클래스를 보겠습니다. –

+0

@SotiriosDelimanolis 편집 됨. – pasemes

답변

4

해결 방법을 알아 냈지만 아직 해결되지 않은 문제가 몇 가지 있습니다.

1) 아직도 UserServiceUserDetailsService 일 때 스프링 컨텍스트 초기화가 실패하는 이유를 모르겠습니다.내가 사용자 정의 AuthenticationProvider을 사용하고 있기 때문에 사용법을 보지 못했다는 점을 감안할 때, 나는이 구현을 제거하고 지금은 괜찮습니다. 사용자 정의 AuthenticationProvider 또는 UserDetailsService 구현을 제공하는 내 지식 (최선을 다해 봄 보안 참조 문서를 처음 읽었을 때 이해할 수있는 것부터)은 독점적 인 대안입니다. 나는 손으로 ApplicatinoAuthenticationProvider를 인스턴스화 한 응답자 (@Sotirios Delimanolis) 중 하나에 의해 발견과는 Spring에 의해 관리되고 있지 된 이후이 인스턴스가 그것으로 autowire가 UserService 인스턴스를하지 않았을으로

2).

@Configuration 
@EnableWebSecurity 
public class WebSecurityConfig extends WebSecurityConfigurerAdapter { 

    @Autowired 
    private ApplicationAuthenticationProvider authenticationProvider; 

    @Override 
    protected void configure(AuthenticationManagerBuilder authManagerBuilder) throws Exception { 
     authManagerBuilder.authenticationProvider(authenticationProvider); 
    } 
} 

이 여전히 충분하지, ApplicationAuthenticationProviderWebSecurityConfig에 autowire가되지 않았기 때문에 아래 볼 수 있듯이이를 바탕으로, 나는 ApplicationAuthenticationProvider의 autowire가 인스턴스를 얻을 수 WebSecurityConfig을 변경했습니다. 이 링크를 기반으로 Spring Security 3.1.3 @Autowired not Work when using WebApplicationInitializer 보안 구성에 구성 요소 검사 선언이 있어야하기 때문에이 메시지가 나타났습니다. @ComponentScan(basePackages = {"com.mypackage"})WebSecurityConfig을 추가하면 문제가 해결되었습니다.

3

내가 그 UserService 가정거야 클래스이며 자체 또는 그 방법 중 하나 중 일부 @Transactional 주석이 있습니다.

당신은 당신의 클래스 패스에 CGLIB를 추가하고 변경해야합니다 당신의 @EnableTransactionManagement

@EnableTransactionManagement(proxyTargetClass = true) 

에하는 것은 그래서 봄이 CGLIB의 프록시를 사용합니다 (이 할 수있는 프록시 클래스) 대신 JKD의 프록시 (이 없습니다).


또는, 인터페이스 UserService을 만들고 구현 (및 @Service와 주석)를 UserServiceImpl 클래스 수 있습니다. autowired UserService 필드는 동일하게 유지되지만 Spring은 JDK 프록시를 사용할 수 있습니다.

+0

@EnableTransactionManagement (proxyTargetClass = true) 주석을 UserService 클래스에 추가했습니다. 오류가 org.springframework.beans.factory.BeanCreationException으로 변경되었습니다 : 'evidenceEditorController'라는 이름으로 bean을 생성하는 중 오류 발생 : 자동 종속 종속성의 삽입이 실패했습니다. 중첩 예외는 org.springframework.beans.factory.BeanCreationException : 필드를 autowire 수 없습니다 : 개인 com.evidencefactory.service.TermService com.evidencefactory.controller.EvidenceEditorController.termService; 중첩 예외는 org.springframework.beans.factory.BeanCreationException : ... – pasemes

+0

@pasemes 주석은'UserService'가 아니라'WebConfig'에 있습니다. –

+0

WebSecurityConfig 및 WebSecurityInitializer 구성 클래스가없는 Spring Security Java 구성을 사용하지 않으면이 오류가 발생하지 않습니다. 나는이 행동을 이해하지 못한다. – pasemes