2016-09-18 60 views
4

我使用Spring MVC测试弹簧试验返回401不安全的网址

这里是我的测试类

@RunWith(SpringRunner.class) 
@WebMvcTest 
public class ITIndexController { 

    @Autowired 
    WebApplicationContext context; 

    MockMvc mockMvc; 

    @MockBean 
    UserRegistrationApplicationService userRegistrationApplicationService; 

    @Before 
    public void setUp() { 
     this.mockMvc = MockMvcBuilders 
         .webAppContextSetup(context) 
         .apply(springSecurity()) 
         .build(); 
    } 

    @Test 
    public void should_render_index() throws Exception { 
     mockMvc.perform(get("/")) 
      .andExpect(status().isOk()) 
      .andExpect(view().name("index")) 
      .andExpect(content().string(containsString("Login"))); 
    } 
} 

这里是MVC配置

@Configuration 
@EnableWebMvc 
public class MvcConfig extends WebMvcConfigurerAdapter { 
    @Override 
    public void addViewControllers(ViewControllerRegistry registry) { 
     registry.addViewController("/").setViewName("index"); 
     registry.addViewController("/login/form").setViewName("login"); 
    } 
} 

这里是安全配置

@Configuration 
@EnableWebSecurity 
public class SecurityConfig extends WebSecurityConfigurerAdapter { 

    @Autowired 
    @Qualifier("customUserDetailsService") 
    UserDetailsService userDetailsService; 

    @Override 
    protected void configure(HttpSecurity http) throws Exception { 
     http.authorizeRequests() 
      .antMatchers("/resources/**", "/signup", "/signup/form", "/").permitAll() 
      .anyRequest().authenticated() 
       .and() 
      .formLogin() 
       .loginPage("/login/form").permitAll().loginProcessingUrl("/login").permitAll() 
       .and() 
      .logout().logoutSuccessUrl("/login/form?logout").permitAll() 
       .and() 
      .csrf().disable(); 
    } 

    @Autowired 
    public void configureGlobalFromDatabase(AuthenticationManagerBuilder auth) throws Exception { 
     auth.userDetailsService(userDetailsService); 
    } 
} 

当我运行我的测试失败消息:

java.lang.AssertionError: Status expected:<200> but was:<401> 
at org.springframework.test.util.AssertionErrors.fail(AssertionErrors.java:54) 
at org.springframework.test.util.AssertionErrors.assertEquals(AssertionErrors.java:81) 
at org.springframework.test.web.servlet.result.StatusResultMatchers$10.match(StatusResultMatchers.java:664) 
at org.springframework.test.web.servlet.MockMvc$1.andExpect(MockMvc.java:171) 
at com.marco.nutri.integration.web.controller.ITIndexController.should_render_index(ITIndexController.java:46) 
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) 
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) 
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) 
at java.lang.reflect.Method.invoke(Method.java:498) 
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50) 
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12) 
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47) 
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17) 
at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:26) 
at org.springframework.test.context.junit4.statements.RunBeforeTestMethodCallbacks.evaluate(RunBeforeTestMethodCallbacks.java:75) 
at org.springframework.test.context.junit4.statements.RunAfterTestMethodCallbacks.evaluate(RunAfterTestMethodCallbacks.java:86) 
at org.springframework.test.context.junit4.statements.SpringRepeat.evaluate(SpringRepeat.java:84) 
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325) 
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:252) 
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:94) 
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290) 
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71) 
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288) 
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58) 
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268) 
at org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61) 
at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:70) 
at org.junit.runners.ParentRunner.run(ParentRunner.java:363) 
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:191) 
at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:86) 
at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38) 
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:459) 
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:678) 
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:382) 
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:192) 

我明白,它不能由于该URL保护带弹簧的安全性,但是当我运行我的应用程序可以访问该网址,即使没有被认证。

我做错了什么?

+0

是否与浏览器相同的配置要求的工作? – chrylis

+0

是的,它确实有效 –

+0

然后,你的测试配置就像是一个问题。如果你在'configure'中放置一个断点并调试测试,会发生什么? – chrylis

回答

5

我找到了答案
春天文档说:

@WebMvcTest会自动配置Spring MVC的基础设施和 限制扫描豆@Controller,@ControllerAdvice,@JsonComponent, 过滤,WebMvcConfigurer和HandlerMethodArgumentResolver。 Regular @使用此批注时,组件bean将不会被扫描。

而且根据这个问题在github上:

https://github.com/spring-projects/spring-boot/issues/5476

由默认的自动配置Spring Security的@WebMvcTest如果弹簧安全测试中存在的类路径(这在我的情况是)。

因此,由于没有选择WebSecurityConfigurer类,所以默认安全性是自动配置的,这就是我在URL中收到401的动机,这在我的安全配置中没有得到保护。 Spring安全默认的自动配置通过基本身份验证保护所有url。

我没有什么要解决的问题是注释与@ContextConfiguration类,并@MockBean喜欢它的文档中描述:

通常@WebMvcTest将被限制在单一的控制器和使用 与@MockBean结合,为 需要的合作者提供模拟实现。

这里是测试类

@RunWith(SpringRunner.class) 
@WebMvcTest 
@ContextConfiguration(classes={Application.class, MvcConfig.class, SecurityConfig.class}) 
public class ITIndex { 

    @Autowired 
    WebApplicationContext context; 

    MockMvc mockMvc; 

    @MockBean 
    UserRegistrationApplicationService userRegistrationApplicationService; 

    @MockBean 
    UserDetailsService userDetailsService; 

    @Before 
    public void setUp() { 
     this.mockMvc = MockMvcBuilders 
         .webAppContextSetup(context) 
         .apply(springSecurity()) 
         .build(); 
    } 

    @Test 
    public void should_render_index() throws Exception { 
     mockMvc.perform(get("/")) 
      .andExpect(status().isOk()) 
      .andExpect(view().name("index")) 
      .andExpect(content().string(containsString("Login"))); 
    } 
} 

应用,MvcConfig和SecurityConfig是我所有的配置类

+3

你可能不需要使用'@ ContextConfiguration'。只需简单地添加'@Import(SecurityConfig.class)'就足够了。 –

+0

有关更多详细信息,请参阅:https://github.com/spring-projects/spring-boot/issues/6514 –