Spring boot 使用@WithMockUser的放心测试用于GET请求,但不用于POST(403错误)

Spring boot 使用@WithMockUser的放心测试用于GET请求,但不用于POST(403错误),spring-boot,post,http-status-code-403,rest-assured,Spring Boot,Post,Http Status Code 403,Rest Assured,在我的SpringBoot2应用程序中,我正在使用Rest Assured测试我的一个控制器。该控制器在类级别映射为/routing status,具有3个端点:一个GET all、一个GET by ID和一个POST 我为GET端点所做的放心测试工作得很好,但不管出于什么原因,POST测试一直导致403错误。(java.lang.AssertionError:1预期失败。 预期状态代码,但它是。)考虑到整个控制器的安全性是相同的,并且我的测试对每个端点使用相同的模拟用户配置,我不知道为什么 也

在我的SpringBoot2应用程序中,我正在使用Rest Assured测试我的一个控制器。该控制器在类级别映射为
/routing status
,具有3个端点:一个GET all、一个GET by ID和一个POST

我为GET端点所做的放心测试工作得很好,但不管出于什么原因,POST测试一直导致403错误。(
java.lang.AssertionError:1预期失败。
预期状态代码,但它是。
)考虑到整个控制器的安全性是相同的,并且我的测试对每个端点使用相同的模拟用户配置,我不知道为什么

也许是安全设置的其他问题只影响帖子(或者至少不影响GET)?下面是我当前的安全配置,尽管我一直在使用端点通配符(但没有用),以查看不使用尾随斜杠是否可行

httpSecurity
            .csrf().csrfTokenRepository(csrfTokenRepository)
            .and().cors()
            .and().addFilter(createCasAuthFilter())
            .headers().frameOptions().disable()
            .and().exceptionHandling().authenticationEntryPoint(noRedirectAuthenticationEntryPoint)
            .and().authorizeRequests()
            .antMatchers(HttpMethod.OPTIONS).permitAll()
            .antMatchers("/login/redirect").authenticated()
            .antMatchers("/login/**", "/status/**", "/error/**", "/smoke-test/**", LOGOUT_PATH).permitAll()
        // BELOW IS THE CONTROLLER ENDPOINT IN QUESTION    
            .antMatchers("/routing-status/**").hasRole("ROUTING_STATUS_ADMIN")
        // ABOVE IS THE CONTROLLER ENDPOINT IN QUESTION
            .antMatchers(HttpMethod.GET, "/user/**").authenticated()
            .antMatchers("/hello-user**", "/exit-user**", "/roles-map**").authenticated()
            .anyRequest().denyAll().and()
            .logout()
            .logoutRequestMatcher(new AntPathRequestMatcher(LOGOUT_PATH))
            .logoutSuccessUrl(casUrl + LOGOUT_PATH)
            .and().authorizeRequests();
下面是我失败的后放心测试。GET请求都使用具有相同常量值的完全相同的
@WithMockUser
注释,并且它们都到达相同的根端点
/routing status
(不过在GET by ID的情况下,会传递额外的
/{ID}
)。我试着在帖子URL中包含尾随斜杠,并将尾随斜杠去掉,但没有成功

private static final String ADMIN_ROLE = "ROUTING_STATUS_ADMIN";


/* Other fields and methods omitted */

@Test
@WithMockUser(username = TEST_USERNAME, roles = {ADMIN_ROLE})
public void testInsertRoutingStatus() {
    RoutingStatus status = createRoutingStatus();

    RoutingStatus result = given().mockMvc(mockMvc).contentType(ContentType.JSON).log().all()
            .and().body(status)
            .when().post("/routing-status/")
            .then().log().all().statusCode(201)
            .and().body(matchesJsonSchemaInClasspath("json-schemas/routing-status.json"))
            .extract().as(RoutingStatus.class);
}
为便于测量,以下是控制器的相关部分:

@Controller
@RequestMapping(value = "/routing-status", produces = MediaType.APPLICATION_JSON_VALUE)
public class RoutingStatusController {
    /* Other properties and endpoints omitted */

    @PostMapping(value = "")
    public ResponseEntity<RoutingStatus> insertRoutingStatus(
        @Valid @RequestBody final RoutingStatus routingStatus, final Principal principal) {

        return new ResponseEntity<>(routingStatusService.saveNewRoutingStatus(routingStatus, principal.getName()),
            HttpStatus.CREATED);
    }
}

看来csrf可能是个问题?但是,当应用程序运行时,csrf工作正常,我不确定它为什么要检查
http://localhost/routing-status
。在本地运行时,在
localhost
/routing status
之间有一个端口号和上下文路径。我得到403的原因是测试中没有CSRF令牌。我不太熟悉CSRF,但根据我目前发现的情况,它不会影响GET请求,因为CSRF只影响POST和PUT之类的写请求。我仍在努力将CSRF步骤添加到重新启动的测试中,但至少我现在知道了这种行为的原因。我打算按照Rest Assured的github页面上的说明完全解决这个问题:

我得到403的原因是测试中没有CSRF令牌。我不太熟悉CSRF,但根据我目前发现的情况,它不会影响GET请求,因为CSRF只影响POST和PUT之类的写请求。我仍在努力将CSRF步骤添加到重新启动的测试中,但至少我现在知道了这种行为的原因。我打算按照Rest Assured的github页面上的说明完全解决此问题:

此问题的完美解决方案如下:

import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.csrf;

@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.DEFINED_PORT)
public class TestClass {
    @Autowired
    private WebApplicationContext webApplicationContext;

   @BeforeEach
   public void setUp() {
     RestAssuredMockMvc.webAppContextSetup(webApplicationContext);
     RestAssuredMockMvc.postProcessors(csrf().asHeader());
   }
}

此问题的最佳解决方案如下:

import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.csrf;

@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.DEFINED_PORT)
public class TestClass {
    @Autowired
    private WebApplicationContext webApplicationContext;

   @BeforeEach
   public void setUp() {
     RestAssuredMockMvc.webAppContextSetup(webApplicationContext);
     RestAssuredMockMvc.postProcessors(csrf().asHeader());
   }
}

您是否尝试过打开SpringSecurity的调试日志,看看他们说了些什么
logging.level.org.springframework.security=DEBUG
application.properties
中,或者在
@EnableWebSecurity(DEBUG=true)
@thomasand中添加注释似乎不起作用,但属性中的日志记录级别起作用。我将用输出更新问题。您是否尝试过为spring security打开调试日志,并查看它们的说明
logging.level.org.springframework.security=DEBUG
application.properties
中,或者在
@EnableWebSecurity(DEBUG=true)
@thomasand中添加注释似乎不起作用,但属性中的日志记录级别起作用。我将用输出更新问题。