簡體   English   中英

如何使用 MockMVC 和 Spring Boot OAuth2 資源服務器測試 http 狀態碼 401(未驗證)?

[英]How to test http status code 401 (unauthenticated) with MockMVC and Spring Boot OAuth2 Resource Server?

我目前正在開發一個 Spring Boot 3應用程序,它提供一個 REST API。要使用這個 API,用戶必須通過我們的身份提供商密鑰斗篷的 OAuth2 工作流程進行身份驗證。 因此,我使用了org.springframework.boot:spring-boot-starter-oauth2-resource-server 當我運行應用程序時,身份驗證和授權按預期工作。

不幸的是,當用戶未提供 JWT 進行身份驗證時,我無法為用例編寫WebMvcTest 在這種情況下,我期望狀態代碼為401 (未驗證)的 HTTP 響應,但我得到狀態代碼 403 (禁止)。 這個事件是否可能是因為 MockMvc 模擬了部分響應處理?

我已經成功地為以下用例編寫了測試用例。

  • 用戶提供了一個 JWT 和預期的聲明 => 我期望狀態代碼 200 ✔
  • 用戶提供了一個 JWT 而沒有預期的聲明 => 我期望狀態代碼 403 ✔

我試圖遵循 Spring 安全文檔中的所有內容: https://docs.spring.io/spring-security/reference/servlet/test/index.html

這是我的代碼。

@WebMvcTest(CustomerController.class)
@ImportAutoConfiguration(classes = {RequestInformationExtractor.class})
@ContextConfiguration(classes = SecurityConfiguration.class)
@Import({TestConfiguration.class, CustomerController.class})
public class PartnerControllerTest {

    @Autowired
    private WebApplicationContext context;

    private MockMvc mockMvc;

    @BeforeEach
    public void setup() {
        mockMvc = MockMvcBuilders
            .webAppContextSetup(context)
            .apply(springSecurity())
            .build();
    }
    
    // runs successfully
    @Test
    void shouldReturnListOfCustomers() throws Exception {
        mockMvc.perform(
                    post("/search")
                        .contentType(MediaType.APPLICATION_JSON)
                        .content("{" +
                                "\"searchKeyword\": \"Mustermann\"" +
                                "}")
                        .with(jwt()
                                .authorities(
                                        new SimpleGrantedAuthority("basic")
                                )))
        .andExpect(status().isOk());
    }

    // fails: expect 401 but got 403
    @Test
    void shouldReturn401WithoutJwt() throws Exception {
        mockMvc.perform(
                post("/search")
                        .contentType(MediaType.APPLICATION_JSON)
                        .content("{" +
                                "\"searchKeyword\": \"Mustermann\"" +
                                "}"))
        .andExpect(status().isUnauthorized());
    }

    // runs successfully
    @Test
    void shouldReturn403() throws Exception {

        mockMvc.perform(
                post("/search")
                        .contentType(MediaType.APPLICATION_JSON)
                        .content("{" +
                                "\"searchKeyword\": \"Mustermann\"" +
                                "}")
                        .with(jwt()))
          .andExpect(status().isForbidden());
    }
}
@org.springframework.boot.test.context.TestConfiguration
public class TestConfiguration {

    @Bean
    public JwtDecoder jwtDecoder() {
        SecretKey secretKey = new SecretKeySpec("dasdasdasdfgsg9423942342394239492349fsd9fsd9fsdfjkldasd".getBytes(), JWSAlgorithm.HS256.getName());
        NimbusJwtDecoder jwtDecoder = NimbusJwtDecoder.withSecretKey(secretKey).build();
        return jwtDecoder;
    }
}
@Configuration
@EnableWebSecurity
public class SecurityConfiguration {

    @Bean
    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
        http
                .sessionManagement(sessionManagement -> sessionManagement.sessionCreationPolicy(STATELESS))
                .authorizeHttpRequests((authz) -> authz
                        .requestMatchers("/actuator/**").permitAll()
                        .anyRequest().hasAuthority("Basic")
                )
                .oauth2ResourceServer(OAuth2ResourceServerConfigurer::jwt);
        return http.build();
    }

    @Bean
    public JwtAuthenticationConverter jwtAuthenticationConverter() {
        JwtGrantedAuthoritiesConverter grantedAuthoritiesConverter = new JwtGrantedAuthoritiesConverter();
        grantedAuthoritiesConverter.setAuthoritiesClaimName("groups");
        grantedAuthoritiesConverter.setAuthorityPrefix("");

        JwtAuthenticationConverter jwtAuthenticationConverter = new JwtAuthenticationConverter();
        jwtAuthenticationConverter.setJwtGrantedAuthoritiesConverter(grantedAuthoritiesConverter);
        return jwtAuthenticationConverter;
    }
}

您可能有一個 403,因為在評估訪問控制(CORS 或 CSRF 或其他)之前拋出異常。

例如,在您的安全配置中,您禁用會話(會話創建策略為無狀態)但不禁用 CSRF 保護。 在您的 conf 中禁用 CSRF(您可以因為 CSRF 攻擊使用會話)或在您的測試中使用 MockMvc csrf()后處理器。

在我的示例教程中,我有許多帶有安全配置和測試(單元和集成)的資源服務器演示。 大多數都引用了我的測試注釋和引導啟動器(它可以在沒有 Java conf 的情況下從屬性定義幾乎所有的安全 conf),但是這個沒有使用我的擴展中的任何內容。 您應該在那里找到有關您的安全配置和測試的有用提示。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM