Spring 安全配置自动装配自定义 UserDetailsService bean
Spring Security config autowiring custom UserDetailsService bean
我最近回到了我一直在做的 Spring 项目,但在启动应用程序时我 运行 遇到了问题。这个问题可能是重复的,但我一直没能找到答案。
这是我原来的片段 SecurityConfig.java:
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired private UserService userService;
/**
* Global security config to set the user details service etc.
* @param auth authentication manager
* @throws Exception
*/
@Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth
.userDetailsService(userService)
.passwordEncoder(passwordEncoder());
}
UserService 对象实现了 UserDetailsService。这在启动时给出了错误:
Caused by: org.springframework.beans.factory.BeanCreationException: Could not autowire field: private com.clubmate.web.service.UserService com.clubmate.web.config.SecurityConfig.userService; nested exception is java.lang.IllegalArgumentException: Can not set com.clubmate.web.service.UserService field com.clubmate.web.config.SecurityConfig.userService to com.sun.proxy.$Proxy62
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:573)
at org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:88)
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.java:331)
... 58 more
Caused by: java.lang.IllegalArgumentException: Can not set com.clubmate.web.service.UserService field com.clubmate.web.config.SecurityConfig.userService to com.sun.proxy.$Proxy62
at sun.reflect.UnsafeFieldAccessorImpl.throwSetIllegalArgumentException(UnsafeFieldAccessorImpl.java:167)
at sun.reflect.UnsafeFieldAccessorImpl.throwSetIllegalArgumentException(UnsafeFieldAccessorImpl.java:171)
at sun.reflect.UnsafeObjectFieldAccessorImpl.set(UnsafeObjectFieldAccessorImpl.java:81)
at java.lang.reflect.Field.set(Field.java:764)
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:569)
... 60 more
根据我的阅读,这是因为我正在自动装配具体 class 而不是 UserDetailsService 接口,但这对我来说很奇怪,因为当我之前在这个项目上工作时,自动装配具体 class 工作正常。
我让步了,只是将其更改为自动装配 SecurityConfig.java 中的 UserDetailsService 接口。
我不确定这是否相关,但现在在启动时我收到以下错误,因为我的任何其他 bean 对象(@Service
s 等)具有 @Autowire private UserService userService
.
Caused by: org.springframework.beans.factory.BeanCreationException: Could not autowire field: private com.clubmate.web.service.UserService com.clubmate.web.service.PageService.userService; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [com.clubmate.web.service.UserService] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)}
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:573)
at org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:88)
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.java:331)
... 58 more
Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [com.clubmate.web.service.UserService] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)}
at org.springframework.beans.factory.support.DefaultListableBeanFactory.raiseNoSuchBeanDefinitionException(DefaultListableBeanFactory.java:1373)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1119)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1014)
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:545)
... 60 more
非常感谢任何帮助。这让我抓狂了几个小时。
更新
更多信息:我有另一个配置 class (AppConfig.java),其中包含以下内容:
@Configuration
@EnableWebMvc
@ComponentScan("com.clubmate.web")
@PropertySource(value = { "classpath:application.properties" })
@Import({
SecurityConfig.class,
CacheConfig.class,
DatabaseConfig.class,
CronConfig.class
})
public class AppConfig extends WebMvcConfigurerAdapter {
// ...
}
我还有两个应用初始化程序 classes,一个用于 MVC,它是:
public class ServletInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {
@Override
public Class<?>[] getRootConfigClasses() {
return new Class[] {
AppConfig.class
};
}
@Override
public Class<?>[] getServletConfigClasses() {
return new Class[] {
StartupHousekeeping.class,
ShutdownHousekeeping.class
};
}
@Override
public String[] getServletMappings() {
return new String[] {
"/"
};
}
}
...另一个安全性是:
public class AppInitializer extends AbstractSecurityWebApplicationInitializer {
private static Logger log = LogManager.getLogger(AppInitializer.class);
@Override
protected void beforeSpringSecurityFilterChain(ServletContext context) {
// load multipart filter before other filters are created
// see: http://docs.spring.io/spring-security/site/docs/4.0.1.RELEASE/reference/htmlsingle/#csrf-multipart
MultipartFilter multipartFilter = new MultipartFilter();
multipartFilter.setMultipartResolverBeanName("multipartResolver");
insertFilters(context, multipartFilter);
}
}
这些会不会有什么冲突?
更新 2
异常抛出处截图:http://i.imgur.com/r6AsOob.jpg
var1 是 SecurityConfig class,var2 是 Proxy 对象,应该是我的 UserService class.
感谢评论中的@fateddy,解决方案是添加
@EnableAspectJAutoProxy(proxyTargetClass=true)
到我的 AppConfig class,然后将 org.aspectj 库导入我的项目。
自动装配失败,因为默认情况下 Spring 使用 JDK-动态代理(通过实现其接口代理目标 class)创建代理。
另一方面,基于 CGLIB 的代理是目标 class.
的子classes
参见:What is the difference between JDK dynamic proxy and CGLib?
要启用基于 CGLIB 的代理,请使用 @EnableAspectJAutoProxy(proxyTargetClass=true)
:
注释您的 @Configuration
classes 之一
@Configuration
@EnableAspectJAutoProxy(proxyTargetClass=true)
public class AppConfig {
...
}
Note that as of version 3.2 CGLIB is repackaged and included in the spring-core JAR. Therefore it will work right out of the box.
我最近回到了我一直在做的 Spring 项目,但在启动应用程序时我 运行 遇到了问题。这个问题可能是重复的,但我一直没能找到答案。
这是我原来的片段 SecurityConfig.java:
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired private UserService userService;
/**
* Global security config to set the user details service etc.
* @param auth authentication manager
* @throws Exception
*/
@Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth
.userDetailsService(userService)
.passwordEncoder(passwordEncoder());
}
UserService 对象实现了 UserDetailsService。这在启动时给出了错误:
Caused by: org.springframework.beans.factory.BeanCreationException: Could not autowire field: private com.clubmate.web.service.UserService com.clubmate.web.config.SecurityConfig.userService; nested exception is java.lang.IllegalArgumentException: Can not set com.clubmate.web.service.UserService field com.clubmate.web.config.SecurityConfig.userService to com.sun.proxy.$Proxy62
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:573)
at org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:88)
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.java:331)
... 58 more
Caused by: java.lang.IllegalArgumentException: Can not set com.clubmate.web.service.UserService field com.clubmate.web.config.SecurityConfig.userService to com.sun.proxy.$Proxy62
at sun.reflect.UnsafeFieldAccessorImpl.throwSetIllegalArgumentException(UnsafeFieldAccessorImpl.java:167)
at sun.reflect.UnsafeFieldAccessorImpl.throwSetIllegalArgumentException(UnsafeFieldAccessorImpl.java:171)
at sun.reflect.UnsafeObjectFieldAccessorImpl.set(UnsafeObjectFieldAccessorImpl.java:81)
at java.lang.reflect.Field.set(Field.java:764)
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:569)
... 60 more
根据我的阅读,这是因为我正在自动装配具体 class 而不是 UserDetailsService 接口,但这对我来说很奇怪,因为当我之前在这个项目上工作时,自动装配具体 class 工作正常。
我让步了,只是将其更改为自动装配 SecurityConfig.java 中的 UserDetailsService 接口。
我不确定这是否相关,但现在在启动时我收到以下错误,因为我的任何其他 bean 对象(@Service
s 等)具有 @Autowire private UserService userService
.
Caused by: org.springframework.beans.factory.BeanCreationException: Could not autowire field: private com.clubmate.web.service.UserService com.clubmate.web.service.PageService.userService; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [com.clubmate.web.service.UserService] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)}
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:573)
at org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:88)
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.java:331)
... 58 more
Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [com.clubmate.web.service.UserService] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)}
at org.springframework.beans.factory.support.DefaultListableBeanFactory.raiseNoSuchBeanDefinitionException(DefaultListableBeanFactory.java:1373)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1119)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1014)
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:545)
... 60 more
非常感谢任何帮助。这让我抓狂了几个小时。
更新
更多信息:我有另一个配置 class (AppConfig.java),其中包含以下内容:
@Configuration
@EnableWebMvc
@ComponentScan("com.clubmate.web")
@PropertySource(value = { "classpath:application.properties" })
@Import({
SecurityConfig.class,
CacheConfig.class,
DatabaseConfig.class,
CronConfig.class
})
public class AppConfig extends WebMvcConfigurerAdapter {
// ...
}
我还有两个应用初始化程序 classes,一个用于 MVC,它是:
public class ServletInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {
@Override
public Class<?>[] getRootConfigClasses() {
return new Class[] {
AppConfig.class
};
}
@Override
public Class<?>[] getServletConfigClasses() {
return new Class[] {
StartupHousekeeping.class,
ShutdownHousekeeping.class
};
}
@Override
public String[] getServletMappings() {
return new String[] {
"/"
};
}
}
...另一个安全性是:
public class AppInitializer extends AbstractSecurityWebApplicationInitializer {
private static Logger log = LogManager.getLogger(AppInitializer.class);
@Override
protected void beforeSpringSecurityFilterChain(ServletContext context) {
// load multipart filter before other filters are created
// see: http://docs.spring.io/spring-security/site/docs/4.0.1.RELEASE/reference/htmlsingle/#csrf-multipart
MultipartFilter multipartFilter = new MultipartFilter();
multipartFilter.setMultipartResolverBeanName("multipartResolver");
insertFilters(context, multipartFilter);
}
}
这些会不会有什么冲突?
更新 2
异常抛出处截图:http://i.imgur.com/r6AsOob.jpg
var1 是 SecurityConfig class,var2 是 Proxy 对象,应该是我的 UserService class.
感谢评论中的@fateddy,解决方案是添加
@EnableAspectJAutoProxy(proxyTargetClass=true)
到我的 AppConfig class,然后将 org.aspectj 库导入我的项目。
自动装配失败,因为默认情况下 Spring 使用 JDK-动态代理(通过实现其接口代理目标 class)创建代理。 另一方面,基于 CGLIB 的代理是目标 class.
的子classes参见:What is the difference between JDK dynamic proxy and CGLib?
要启用基于 CGLIB 的代理,请使用 @EnableAspectJAutoProxy(proxyTargetClass=true)
:
@Configuration
classes 之一
@Configuration
@EnableAspectJAutoProxy(proxyTargetClass=true)
public class AppConfig {
...
}
Note that as of version 3.2 CGLIB is repackaged and included in the spring-core JAR. Therefore it will work right out of the box.