我正在尝试为具有方法级安全控制器的Spring-Boot应用程序设置RestAssured测试。
例如,我有使用方法级别安全性的最小控制器
@RestController
public class DummyController {
@GetMapping("/")
@PreAuthorize("hasRole('TEST')") // removing this should make the test green
public String test() {
return "hello";
}
}
和许可的安全配置
@Configuration@EnableGlobalMethodSecurity(prePostEnabled = true)public class SecurityConfig extends WebSecurityConfigurerAdapter { @Override protected void configure(HttpSecurity http) throws Exception { http.authorizeRequests().anyRequest().permitAll(); }}
然后,使用RestAssured进行的这个简单测试失败了:
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)@RunWith(SpringRunner.class)public class DummyControllerITest { private static final Logger logger = LoggerFactory.getLogger(DummyControllerITest.class); @LocalServerPort private int port; @Test @WithMockUser(roles = "TEST") public void name() throws Exception { RestAssured.given() .port(port) .when() .get("/") .then() .statusCode(HttpStatus.OK.value()); }}
即使模拟用户配置了正确的角色,此测试为什么也会失败?
我已对此进行调试,看来运行测试的线程中的SecurityContext设置正确,而未处理处理RestAssured请求的线程中的SecurityContext。但为什么?
最佳答案
因此,我终于弄清楚了什么地方出了问题。这是我发现的:
注入SecurityContext仅在单元测试中才有意义,但是原始测试试图成为集成测试。
有两种解决方法:
使测试成为适当的单元测试。然后,您应该使用RestAssuredMockMvc.given()
而不是RestAssured.given()
。例如,
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.MOCK)
@RunWith(SpringRunner.class)
public class DummyControllerITest {
@Autowired
private WebApplicationContext webAppContextSetup;
@Test
@WithMockUser(roles = "TEST")
public void name() throws Exception {
RestAssuredMockMvc.webAppContextSetup(webAppContextSetup);
RestAssuredMockMvc.given()
.when()
.get("/")
.then()
.statusCode(HttpStatus.OK.value());
RestAssuredMockMvc.reset();
}
}
可以使用,但那时只能进行单元测试。
使测试成为适当的集成测试。这将涉及建立适当的身份验证,并配置测试请求的主体,以使SecurityContext将按生产代码的要求进行填充。然后使用RestAssured沿着那条路线走,看起来就像是沿着这些路线:
@Test
@WithMockUser(roles = "TEST")
public void name() throws Exception {
given()
.auth().basic("testuser", "password") // ######
.port(port)
.when()
.get("/")
.then()
.statusCode(HttpStatus.OK.value());
}