我正在尝试进行一些用于测试某些业务控制器的集成测试,以及其他用于进行安全配置的测试。
因此,我有业务控制器测试扩展了BaseTest
类,而安全配置测试扩展了SecurityBaseTest
类。
我只想为执行安全性测试的测试加载安全配置,而不要为业务控制者的测试加载安全性配置,因为这些测试仅应执行控制器而不是安全性配置。
@SpringBootTest(classes = { TestConfiguration.class, WebConfiguration.class })
@RunWith(SpringRunner.class)
public abstract class BaseTest {
@Before
public void setup() throws Exception {
this.mockMvc = MockMvcBuilders.webAppContextSetup(webApplicationContext).addFilters(springSecurityFilterChain).build();
httpHeaders = new HttpHeaders();
}
}
@SpringBootTest(classes = { TestConfiguration.class, SecurityConfiguration.class, WebConfiguration.class })
public abstract class SecurityBaseTest extends BaseTest {
@Before
public void setup() throws Exception {
super.setup();
userFixtureService.addUserFixture();
addTokenToRequestHeader(httpHeaders, UserFixtureService.USER_EMAIL);
}
private void addTokenToRequestHeader(HttpHeaders headers, String username) {
tokenAuthenticationService.addTokenToResponseHeader(headers, username);
}
}
使用命令mvn clean install -Denv="test" -Ddb="h2" -Dtest=UserControllerTest -Dmaven.surefire.debug="-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=5005 -Xnoagent -Djava.compiler=NONE"
运行业务控制器测试时,调试器将显示该安全配置没有正确加载。
但是testCrudOperations
方法失败,因为它返回403
状态,而不是预期的201
状态。并且调试器显示UserController
控制器端点根本没有被命中。
public class UserControllerTest extends BaseTest {
@Test
public void testCrudOperations() throws Exception {
MvcResult mvcResult = this.mockMvc
.perform(post(RESTConstants.SLASH + UserDomainConstants.USERS)
.contentType(MediaType.APPLICATION_JSON).accept(MediaType.APPLICATION_JSON)
.headers(httpHeaders)
.content(jacksonObjectMapper.writeValueAsString(userResource0)))
.andExpect(status().isCreated())
.andExpect(jsonPath("$.firstname").exists())
.andExpect(jsonPath("$.firstname").value(userResource0.getFirstname()))
.andExpect(jsonPath("$.lastname").value(userResource0.getLastname()))
.andExpect(jsonPath("$.email").value(userResource0.getEmail()))
.andExpect(header().string("Location", Matchers.containsString("/users/"))).andReturn();
UserResource retrievedUserResource = deserializeResource(mvcResult, UserResource.class);
assertThatUserResource(retrievedUserResource).hasEmail(userResource0.getEmail());
assertThatUserResource(retrievedUserResource)
.hasRole(retrievedUserResource.getUserRoles().iterator().next().getRole());
userResource0.setResourceId(retrievedUserResource.getResourceId());
}
}
使用命令mvn clean install -Denv="test" -Ddb="h2" -Dtest=UserAuthenticationTest -Dmaven.surefire.debug="-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=5005 -Xnoagent -Djava.compiler=NONE"
运行安全配置测试时,调试器将显示安全配置已正确加载。
但是testUnsecuredResourceGrantsAccess
方法失败,并显示错误No qualifying bean of type 'org.springframework.security.web.FilterChainProxy' available
消息。
public class UserAuthenticationTest extends SecurityBaseTest {
@Test
public void testUnsecuredResourceGrantsAccess() throws Exception {
this.mockMvc.perform(
post(RESTConstants.SLASH + UserDomainConstants.USERS + RESTConstants.SLASH + UserDomainConstants.LOGIN)
.accept(MediaType.APPLICATION_JSON)
)
.andDo(print())
.andExpect(status().isBadRequest())
.andReturn();
}
}
安全配置为:
@EnableWebSecurity(debug = true)
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
@Bean
public AuthenticationFromCredentialsFilter authenticationFromCredentialsFilter() throws Exception {
AuthenticationFromCredentialsFilter authenticationFromCredentialsFilter = new AuthenticationFromCredentialsFilter(new AntPathRequestMatcher("/users/login", RequestMethod.POST.name()));
authenticationFromCredentialsFilter.setAuthenticationManager(authenticationManagerBean());
return authenticationFromCredentialsFilter;
}
@Bean
public AuthenticationFromTokenFilter authenticationFromTokenFilter() throws Exception {
AuthenticationFromTokenFilter authenticationFromTokenFilter = new AuthenticationFromTokenFilter(new NegatedRequestMatcher(new AntPathRequestMatcher("/users/login")));
authenticationFromTokenFilter.setAuthenticationManager(authenticationManagerBean());
return authenticationFromTokenFilter;
}
@Bean
FilterRegistrationBean<AuthenticationFromTokenFilter> disableAutoRegistration(final AuthenticationFromTokenFilter filter) {
final FilterRegistrationBean<AuthenticationFromTokenFilter> registration = new FilterRegistrationBean<AuthenticationFromTokenFilter>(filter);
registration.setEnabled(false);
return registration;
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.cors();
http
.csrf().disable()
.formLogin().disable()
.httpBasic().disable()
.logout().disable();
http.exceptionHandling().authenticationEntryPoint(restAuthenticationEntryPoint);
http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
http.addFilterBefore(simpleCORSFilter, ChannelProcessingFilter.class);
http
.addFilterBefore(authenticationFromTokenFilter, UsernamePasswordAuthenticationFilter.class)
.authorizeRequests()
.antMatchers("/", "/error").permitAll()
.antMatchers("/users/login").permitAll()
.antMatchers("/admin/**").hasRole(UserDomainConstants.ROLE_ADMIN)
.anyRequest().authenticated();
}
}