如何在集成测试中使用 spring security?

问题描述

我有以下 WebSecurityConfigurerAdapter 实现:

@Configuration
@Order(0)
@EnableWebSecurity
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
    private static final List<String> permittedpaths = asList();
    private static final String protectedpath = "";

    private final UserDetailsServiceImpl userDetailsService;
    private final JwtAuthenticationProvider jwtAuthenticationProvider;
    private final DataSource dataSource;

    public SecurityConfiguration(
        UserDetailsServiceImpl userDetailsService,JwtAuthenticationProvider jwtAuthenticationProvider,DataSource dataSource
    ) {
        this.userDetailsService = userDetailsService;
        this.jwtAuthenticationProvider = jwtAuthenticationProvider;
        this.dataSource = dataSource;
    }

    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }

    @Bean
    @Override
    public AuthenticationManager authenticationManagerBean() throws Exception {
        return super.authenticationManagerBean();
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {}

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(userDetailsService);
        auth.authenticationProvider(jwtAuthenticationProvider);
        auth.jdbcAuthentication().dataSource(dataSource)
                .usersByUsernameQuery("")
                .authoritiesByUsernameQuery("")
                .passwordEncoder(passwordEncoder());
    }
}

此安全性适用于正常运行的应用程序。但在测试中 - 失败。 我有一个集成测试,如:

@WebMvcTest(SomeController.class)
@Import({ErrorHandlerConfiguration.class})
class SomeControllerItTest {
    @Autowired
    private mockmvc mockmvc;

    @MockBean
    private RegistrationService registrationService;

    @Test
    void shouldConfirmRegistration() {}
}

运行后,出现以下错误

原因: org.springframework.beans.factory.UnsatisfiedDependencyException: 使用文件中定义的名称“securityConfiguration”创建 bean 时出错 [SecurityConfiguration.class]:表示不满足的依赖 通过构造函数参数0;嵌套异常是 org.springframework.beans.factory.NoSuchBeanDeFinitionException:否 可用的“UserDetailsS​​erviceImpl”类型的合格 bean:预期 至少 1 个 bean 有资格作为自动装配候选者。依赖 注释:{}

当我向这个测试添加 SecurityConfiguration 类 bean 时:

@MockBean
private JwtAuthenticationProvider jwtAuthenticationProvider;
@MockBean
private UserDetailsServiceImpl userDetailsService;
@MockBean
private DataSource dataSource;

测试正常运行,没有任何 NoSuchBeanDeFinitionException 异常。

这个解决方案对我来说还不够。有没有其他方法可以避免将安全 bean 放入每个集成测试中?

我尝试使用:

  • @Import({ErrorHandlerConfiguration.class,SecurityConfiguration.class})
  • @ContextConfiguration(classes = {SecurityConfiguration.class})

没有任何结果。

(为简洁起见,删除方法体和一些字符串)

// 编辑 附加缺失的类,这些类被注入到 SecurityConfiguration:

@Service
public class UserDetailsServiceImpl implements UserDetailsService {
//method implementation
}

@Component
public class JwtAuthenticationProvider implements AuthenticationProvider {
//method implementation
}

解决方法

@WebMvcTest(
    value = SomeController.class,excludeAutoConfiguration = SecurityAutoConfiguration.class,excludeFilters = @ComponentScan.Filter(
            type = FilterType.ASSIGNABLE_TYPE,classes = WebSecurityConfigurer.class))
@AutoConfigureMockMvc(addFilters = false)
public class SomeControllerTest {

    @Autowired
    MockMvc mockMvc;
    
    ...
}
,

这是一个合格的猜测,但由于某种原因,您没有发布缺少 UserDetailsServiceImpl 的课程。

如果您阅读有关 WebMvcTest 的文档,它会指出:

@WebMvcTest 自动配置 Spring MVC 基础结构并将扫描的 bean 限制为 @Controller@ControllerAdvice@JsonComponentConverterGenericConverterFilterHandlerInterceptorWebMvcConfigurerHandlerMethodArgumentResolver

使用 @Component 注释时不会扫描常规 @ConfigurationProperties@WebMvcTest bean。 @EnableConfigurationProperties 可用于包含 @ConfigurationProperties bean。

所以我猜你的 bean 没有因为这个原因被选中,这一切都在 docs 中说明。

但如前所述,这是一个猜测,因为出于某种原因,您没有发布我们缺少的代码供我们查看,并且有几个不知道的地方,例如空构造函数和其他空函数。