在 Spring Boot 中禁用或模拟 OAuth2 以进行集成测试
Disable or mocking OAuth2 for integration test in Spring Boot
我正在尝试 disable/mock 本地 OAuth2 服务器,同时 运行 进行集成测试,但到目前为止,大多数方法都涉及 Spring MVC,我是不使用。这是最常见的解决方案:
this.mockMvc = MockMvcBuilders
.webAppContextSetup(webApplicationContext)
.apply(springSecurity())
.build();
在 Spring 启动时,我有一个 TestRestTemplate
用于端点上的请求。我在测试中有这个:
@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT,
properties = {"eureka.client.enabled:false"})
public class ApiControllerTest {
@Test
@WithOauth2TestAuthentication
public void employeesPost() throws Exception {
HttpHeaders headers = new HttpHeaders();
headers.add(HttpHeaders.AUTHORIZATION, "Bearer FOO");
headers.add(HttpHeaders.CONTENT_TYPE, "application/json");
ResponseEntity<OperationResultDTO> responseEntity =
this.restTemplate.postForEntity("/employees", new HttpEntity<>(loggedEmployee, headers), OperationResultDTO.class);
assertEquals(HttpStatus.UNPROCESSABLE_ENTITY, responseEntity.getStatusCode());
}
}
注解:
@Retention(RetentionPolicy.RUNTIME)
@Target({ ElementType.METHOD })
@WithSecurityContext(factory = WithOAuth2AuthenticationSecurityContextFactory.class)
public @interface WithOauth2TestAuthentication {
String clientId() default "temporal";
String username() default "username";
String[] scopes() default { "read", "write", "trust" };
}
SecurityContextFactory:
public class WithOAuth2AuthenticationSecurityContextFactory
implements WithSecurityContextFactory<WithOauth2TestAuthentication> {
@Override
public SecurityContext createSecurityContext(WithOauth2TestAuthentication annotation) {
Set<String> scopes = new HashSet<>();
Collections.addAll(scopes, annotation.scopes());
OAuth2Request oAuth2Request = new OAuth2Request(null, annotation.clientId(),
null, true, scopes, null, null,
null, null);
Authentication auth2Authentication = new OAuth2Authentication(oAuth2Request,
new TestingAuthenticationToken(annotation.username(), null, "read"));
SecurityContext context = SecurityContextHolder.createEmptyContext();
context.setAuthentication(auth2Authentication);
return context;
}
}
到目前为止,每个测试 运行 都向我抛出一个断言错误,这意味着请求返回 401 而不是我想要的 422。我尝试使用以下说明伪造 OAuth 服务器:http://engineering.pivotal.io/post/faking_oauth_sso/ 无济于事(我也试图避免它,但我的尝试没有成功)。我也可以模拟授权令牌,但我不确定如何在此处执行此操作。
我最后做的是将 OAuth2 配置文件放在不同的 @Profile
上,并为每个控制器测试创建一个摘要 class,并且 也 将 MockMvc 与 @AutoConfigureMockMvc
:
一起使用
@AutoConfigureMockMvc
@SpringBootTest
@ActiveProfiles({ "default", "local", "test" })
abstract class BaseControllerTest {
}
@RunWith(SpringRunner.class)
public class SampleControllerTest extends BaseControllerTest {
@Autowired
private MockMvc mockMvc;
// ...
@Test
@WithMockUser
public void aTest() throws Exception {
MvcResult result =
mockMvc.perform(get(URL_TEMPLATE).with(csrf()))
.andExpect(status().isOk())
.andReturn();
}
}
使用该设置,SecurityContext
会 return 一个模拟用户,这最终导致我的请求因 401 HTTP 代码而失败。如果我需要针对无法处理的实体响应,只需将 status().isOk()
切换为 status().isUnprocessableEntity()
。
我正在尝试 disable/mock 本地 OAuth2 服务器,同时 运行 进行集成测试,但到目前为止,大多数方法都涉及 Spring MVC,我是不使用。这是最常见的解决方案:
this.mockMvc = MockMvcBuilders
.webAppContextSetup(webApplicationContext)
.apply(springSecurity())
.build();
在 Spring 启动时,我有一个 TestRestTemplate
用于端点上的请求。我在测试中有这个:
@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT,
properties = {"eureka.client.enabled:false"})
public class ApiControllerTest {
@Test
@WithOauth2TestAuthentication
public void employeesPost() throws Exception {
HttpHeaders headers = new HttpHeaders();
headers.add(HttpHeaders.AUTHORIZATION, "Bearer FOO");
headers.add(HttpHeaders.CONTENT_TYPE, "application/json");
ResponseEntity<OperationResultDTO> responseEntity =
this.restTemplate.postForEntity("/employees", new HttpEntity<>(loggedEmployee, headers), OperationResultDTO.class);
assertEquals(HttpStatus.UNPROCESSABLE_ENTITY, responseEntity.getStatusCode());
}
}
注解:
@Retention(RetentionPolicy.RUNTIME)
@Target({ ElementType.METHOD })
@WithSecurityContext(factory = WithOAuth2AuthenticationSecurityContextFactory.class)
public @interface WithOauth2TestAuthentication {
String clientId() default "temporal";
String username() default "username";
String[] scopes() default { "read", "write", "trust" };
}
SecurityContextFactory:
public class WithOAuth2AuthenticationSecurityContextFactory
implements WithSecurityContextFactory<WithOauth2TestAuthentication> {
@Override
public SecurityContext createSecurityContext(WithOauth2TestAuthentication annotation) {
Set<String> scopes = new HashSet<>();
Collections.addAll(scopes, annotation.scopes());
OAuth2Request oAuth2Request = new OAuth2Request(null, annotation.clientId(),
null, true, scopes, null, null,
null, null);
Authentication auth2Authentication = new OAuth2Authentication(oAuth2Request,
new TestingAuthenticationToken(annotation.username(), null, "read"));
SecurityContext context = SecurityContextHolder.createEmptyContext();
context.setAuthentication(auth2Authentication);
return context;
}
}
到目前为止,每个测试 运行 都向我抛出一个断言错误,这意味着请求返回 401 而不是我想要的 422。我尝试使用以下说明伪造 OAuth 服务器:http://engineering.pivotal.io/post/faking_oauth_sso/ 无济于事(我也试图避免它,但我的尝试没有成功)。我也可以模拟授权令牌,但我不确定如何在此处执行此操作。
我最后做的是将 OAuth2 配置文件放在不同的 @Profile
上,并为每个控制器测试创建一个摘要 class,并且 也 将 MockMvc 与 @AutoConfigureMockMvc
:
@AutoConfigureMockMvc
@SpringBootTest
@ActiveProfiles({ "default", "local", "test" })
abstract class BaseControllerTest {
}
@RunWith(SpringRunner.class)
public class SampleControllerTest extends BaseControllerTest {
@Autowired
private MockMvc mockMvc;
// ...
@Test
@WithMockUser
public void aTest() throws Exception {
MvcResult result =
mockMvc.perform(get(URL_TEMPLATE).with(csrf()))
.andExpect(status().isOk())
.andReturn();
}
}
使用该设置,SecurityContext
会 return 一个模拟用户,这最终导致我的请求因 401 HTTP 代码而失败。如果我需要针对无法处理的实体响应,只需将 status().isOk()
切换为 status().isUnprocessableEntity()
。