【问题标题】:@WebMvcTest Error creating bean with name 'securityConfiguration'@WebMvcTest 创建名为“securityConfiguration”的 bean 时出错
【发布时间】:2020-09-05 15:50:42
【问题描述】:

我有一个 Spring Boot Rest 应用程序,我在其中使用 JWT 进行身份验证,当我启动应用程序时它工作正常。

我只是想添加一些测试用例,但我无法解决这个问题(我用mvn test 运行测试用例:

错误表明 Spring 无法创建 userDetailsS​​ervice bean,但这似乎不正确,因为我的应用程序可以毫无问题地运行。

不是:我尝试通过 @MockBean 添加 userdetailservice 模拟。但是这次 spring 为 MyAuthenticationEntryPoint 显示了相同的错误。我认为应该有一个解决方案来自动添加所有配置,或者避免所有这些配置。

[ERROR] verifyRegisterUserHttpRequest  Time elapsed: 0.008 s  <<< ERROR!
java.lang.IllegalStateException: Failed to load ApplicationContext
Caused by: org.springframework.beans.factory.UnsatisfiedDependencyException: 
Error creating bean with name 'securityConfiguration': Unsatisfied dependency expressed 
through field 'userDetailsService'; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: 
No qualifying bean of type 'com.myProjects.sample.security.MyUserDetailsService' available: expected at least 1 bean which qualifies as autowire candidate. 
Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)}
  • 这里是测试类:
package com.myProjects.sample.controller;

@WebMvcTest(controllers = RegisterController.class)
public class RegisterControllerTest {
    @Autowired
    private MockMvc mockMvc;
    @Autowired
    private ObjectMapper objectMapper;
    @MockBean
    private RegisterService registerService;
    @MockBean
    private ValidationService validationService;

    // 1. Verifying Http Request Matching
    @Test
    public void verifyRegisterUserHttpRequest() throws Exception {
        NewCustomerRequest requestBody = new NewCustomerRequest();
        requestBody.setEmailAddress("sample@sample.com");
        requestBody.setPhoneNumber("01112223344");
        requestBody.setPassword("password");
        requestBody.setPasswordVerify("password");

        mockMvc.perform(post(MyWebUrls.API.API + MyWebUrls.Register.REGISTER_USER)
                .content(objectMapper.writeValueAsString(requestBody))
                .contentType("application/json"))
                .andExpect(status().isOk());
    }
}
  • RegisterController 和 SecurityConfiguration
package com.myProjects.sample.controller;
@RestController
@RequestMapping(MyWebUrls.API.API)
public class RegisterController {

    @Autowired
    private RegisterService registerService;

    @Autowired
    private ValidationService validationService;

    @PostMapping(MyWebUrls.Register.REGISTER_USER)
    public ResponseEntity<?> registerUser(@Valid @RequestBody NewCustomerRequest newCustomerRequest, BindingResult bindingResult){
        String validationResultMessage = validationService.getFirstValidationErrorMessage(bindingResult);
        // ...
        }
    }
}
package com.myProjects.sample.security;
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(
        // securedEnabled = true,
        // jsr250Enabled = true,
        prePostEnabled = true)
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {

    @Autowired
    private MyUserDetailsService userDetailsService;

    @Autowired
    private MyAuthenticationEntryPoint unauthorizedHandler;

    @Autowired
    private CustomAccessDeniedHandler accessDeniedHandler;

    @Bean
    public AuthTokenFilter authJwtTokenFilter(){
        return new AuthTokenFilter();
    }

    @Override
    public void configure(AuthenticationManagerBuilder authenticationManagerBuilder) throws Exception {
        authenticationManagerBuilder.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder());
    }
    // ....
  • 还可以查看我的自定义详细信息服务类
package com.myProjects.sample.security;
@Service
public class MyUserDetailsService implements UserDetailsService {

    @Override
    @Transactional
    public UserDetails loadUserByUsername(String emailOrMobilePhone) throws UsernameNotFoundException {
        // ...
    }
}

【问题讨论】:

  • 您还需要在测试类中自动装配或模拟您的 userDetialService
  • 我已经尝试过了,但是这次同样的错误发生在名为 AuthenticationEntryPoint 的 bean 上,然后是 Jwt ......我认为在这种情况下应该有一种方法不启用安全性
  • 一种方法是创建配置文件并使用@Profile("!test") 装饰你的spring bean,并在运行测试类时将装饰器保持为@ActiveProfiles("test")

标签: java spring spring-boot spring-test spring-test-mvc


【解决方案1】:

你能在你的项目中添加以下依赖吗?

<dependency>
  <groupId>org.springframework.security</groupId>
  <artifactId>spring-security-test</artifactId>
  <scope>test</scope>
</dependency>

这应该确保也为您的@WebMvcTest 填充您的安全配置。

然后,您可以在使用 MockMvc 访问您的应用程序时使用多种技术来模拟凭据/用户:

@Test
@WithMockUser("duke")

@Test
public void testWithSecurityMockMvcRequestPostProcessors() throws Exception {
  this.mockMvc
    .perform(
      post("/your/endpoint")
        .with(jwt())
        .with(csrf())
    )
    .andExpect(status().isOk());

}

有关MockMvc 和 Spring Security 集成的更多信息,请访问here

【讨论】:

  • 这似乎是正确的方法,我的解决方案是通过@MockBean 注释来注释每个所需的bean。因为这个控制器(RegisterController)不需要Spring Application的保护。毕竟我有这样的 mockbean 对象:@MockBean private MyUserDetailsService userDetailsService; @MockBean private MyAuthenticationEntryPoint unauthorizedHandler; @MockBean private CustomAccessDeniedHandler accessDeniedHandler; @MockBean private JwtUtils jwtUtils;
  • 这样你就可以解决你的问题还是它仍然会发生?
  • @riekpill,是的,我可以修复它,但如果控制器需要保护,我正在使用@SpringBootTestannotation,我想我也可以使用你的解决方案
猜你喜欢
  • 1970-01-01
  • 2021-11-28
  • 2020-10-03
  • 2019-08-28
  • 2015-03-18
  • 2021-03-17
  • 2021-06-18
  • 2019-07-21
  • 2016-04-04
相关资源
最近更新 更多