如果在使用Spring Security时,遇到需要自定义 AuthenticationProvider
的情况,同时自定义的 AuthenticationProvider
中需要使用 @Autowired
注入其他的bean,却发现无法注入的情况,此时可以按照以下步骤进行解决。
问题背景
在使用Spring Security时,如果需要自定义 AuthenticationProvider
,可能需要注入一些其他的bean,例如 UserDetailsService
等。在自定义的 AuthenticationProvider
中使用 @Autowired
或者 @Resource
进行注入时,可能会失败,导致注入的bean为 null
。
解决步骤
1.自定义 AuthenticationProvider
类
首先,我们需要自定义一个 AuthenticationProvider
类,例如下面的代码:
@Component
public class MyAuthenticationProvider implements AuthenticationProvider {
@Autowired
private UserDetailsService userDetailsService;
@Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
// do authentication
}
@Override
public boolean supports(Class<?> aClass) {
return true;
}
}
在这个类中,我们希望通过 @Autowired
注入 UserDetailsService
。
2.创建一个配置类
接下来,我们需要创建一个配置类,将 MyAuthenticationProvider
添加到 Spring Security 配置中,并将 UserDetailsService
注册到 Spring 容器中。例如下面的代码:
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
private MyAuthenticationProvider myAuthenticationProvider;
@Bean
public UserDetailsService userDetailsService() {
// create user details service
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.authenticationProvider(myAuthenticationProvider);
}
@Override
protected void configure(HttpSecurity http) throws Exception {
// configure http security
}
}
在这个配置类中,我们通过 @Autowired
注入了 MyAuthenticationProvider
。同时,我们创建了一个 UserDetailsService
bean,并将其注册到 Spring 容器中。在 configure
方法中,我们将 MyAuthenticationProvider
添加到 AuthenticationManagerBuilder
中。
3.使用 @DependsOn 注解
为了避免 Spring 容器在初始化 MyAuthenticationProvider
时,还未初始化 UserDetailsService
bean,我们可以在 MyAuthenticationProvider
中使用 @DependsOn
注解来保证 bean 初始化的顺序。例如:
@Component
@DependsOn("userDetailsService")
public class MyAuthenticationProvider implements AuthenticationProvider {
@Autowired
private UserDetailsService userDetailsService;
@Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
// do authentication
}
@Override
public boolean supports(Class<?> aClass) {
return true;
}
}
在这个例子中,我们使用 @DependsOn
注解来告诉 Spring 容器,MyAuthenticationProvider
依赖于名为 userDetailsService
的bean。这样确保了在初始化 MyAuthenticationProvider
之前,UserDetailsService
bean已经被初始化。
4.使用 BeanPostProcessor
除了使用 @DependsOn
注解,还可以使用 BeanPostProcessor
来解决这个问题。首先,我们需要创建一个 BeanPostProcessor
类,例如下面的代码:
@Component
public class MyBeanPostProcessor implements BeanPostProcessor {
@Autowired
private UserDetailsService userDetailsService;
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
if (bean instanceof MyAuthenticationProvider) {
((MyAuthenticationProvider) bean).setUserDetailsService(userDetailsService);
}
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
return bean;
}
}
在这个 BeanPostProcessor
类中,我们通过 @Autowired
注入了 UserDetailsService
。然后,在 postProcessBeforeInitialization
方法中,我们对 MyAuthenticationProvider
进行判断并进行设置。
接下来,在我们的 MyAuthenticationProvider
类中,我们要添加 setter 方法来设置 UserDetailsService
:
@Component
public class MyAuthenticationProvider implements AuthenticationProvider {
private UserDetailsService userDetailsService;
public void setUserDetailsService(UserDetailsService userDetailsService) {
this.userDetailsService = userDetailsService;
}
@Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
// do authentication
}
@Override
public boolean supports(Class<?> aClass) {
return true;
}
}
在这个 MyAuthenticationProvider
类中,我们添加了一个 setUserDetailsService
方法,用于设置 UserDetailsService
。
示例演示
以下为两个示例代码:
示例一
@Component
public class MyAuthenticationProvider implements AuthenticationProvider {
@Autowired
private UserDetailsService userDetailsService;
@Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
// do authentication
}
@Override
public boolean supports(Class<?> aClass) {
return true;
}
}
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
private MyAuthenticationProvider myAuthenticationProvider;
@Bean
public UserDetailsService userDetailsService() {
// create user details service
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.authenticationProvider(myAuthenticationProvider);
}
@Override
protected void configure(HttpSecurity http) throws Exception {
// configure http security
}
}
@Component
@DependsOn("userDetailsService")
public class MyAuthenticationProvider implements AuthenticationProvider {
@Autowired
private UserDetailsService userDetailsService;
@Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
// do authentication
}
@Override
public boolean supports(Class<?> aClass) {
return true;
}
}
示例二
@Component
public class MyAuthenticationProvider implements AuthenticationProvider {
private UserDetailsService userDetailsService;
public void setUserDetailsService(UserDetailsService userDetailsService) {
this.userDetailsService = userDetailsService;
}
@Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
// do authentication
}
@Override
public boolean supports(Class<?> aClass) {
return true;
}
}
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
private MyAuthenticationProvider myAuthenticationProvider;
@Bean
public UserDetailsService userDetailsService() {
// create user details service
}
@Autowired
public void setUserDetailsService(UserDetailsService userDetailsService) {
myAuthenticationProvider.setUserDetailsService(userDetailsService);
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.authenticationProvider(myAuthenticationProvider);
}
@Override
protected void configure(HttpSecurity http) throws Exception {
// configure http security
}
}
@Component
public class MyBeanPostProcessor implements BeanPostProcessor {
@Autowired
private UserDetailsService userDetailsService;
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
if (bean instanceof MyAuthenticationProvider) {
((MyAuthenticationProvider) bean).setUserDetailsService(userDetailsService);
}
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
return bean;
}
}
@Component
public class MyAuthenticationProvider implements AuthenticationProvider {
private UserDetailsService userDetailsService;
@Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
// do authentication
}
@Override
public boolean supports(Class<?> aClass) {
return true;
}
public void setUserDetailsService(UserDetailsService userDetailsService) {
this.userDetailsService = userDetailsService;
}
}
本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:SpringSecurity自定义AuthenticationProvider无法@Autowire的解决 - Python技术站