在SpringBootTest中测试COR

问题描述 投票:0回答:6

我正在尝试编写一个测试来验证我们的 CORS 设置。 我是这样配置CORS的。

@Override
    public void configure(HttpSecurity httpSecurity) throws Exception {
//        super.configure(httpSecurity);
        httpSecurity.csrf().disable();
        httpSecurity.authorizeRequests().antMatchers("/**").permitAll();
        httpSecurity.cors();
    }

    @Bean
    public CorsConfigurationSource corsConfigurationSource() {
        CorsConfiguration configuration = new CorsConfiguration();
        List<String> allowedMethods = CORS_ALLOWED_METHODS;
        configuration.setAllowedMethods(allowedMethods);
        configuration.setAllowedOrigins(CORS_ALLOWED_ORIGINS);
        configuration.setAllowedHeaders(CORS_ALLOWED_HEADERS);
        configuration.setAllowCredentials(true);
        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        source.registerCorsConfiguration("/**", configuration);
        return source;
    }

我已经使用调试器验证了当我的测试运行时

CORS_ALLOWED_METHODS
有值。

这是我的测试。 当我在标题上断言时它失败了。

@RunWith(SpringRunner.class)
@SpringBootTest
@ActiveProfiles("dev")
public class ControllerTests {

    @Autowired
    private WebApplicationContext wac;

    public MockMvc mockMvc;

    @Before
    public void setup() {
        DefaultMockMvcBuilder builder = MockMvcBuilders
                .webAppContextSetup(this.wac)
                .apply(SecurityMockMvcConfigurers.springSecurity())
                .dispatchOptions(true);
        this.mockMvc = builder.build();
    }

    @Test
    public void testCors() throws Exception {
        this.mockMvc
                .perform(get("/test-cors"))
                .andDo(print())
                .andExpect(status().isOk())
                .andExpect(header().string("Access-Control-Allow-Methods", "OPTIONS,GET,HEAD,POST,PUT,DELETE,TRACE,CONNECT"))
                .andExpect(content().string("whatever"));
    }

    @SpringBootApplication(scanBasePackages = {"the.packages"})
    @Controller
    static class TestApplication {

        public static void main(String[] args) throws Exception {
            SpringApplication.run(TestApplication.class, args);
        }

        @RequestMapping(value = {"test-cors"},  method = RequestMethod.GET)
        @ResponseStatus(HttpStatus.OK)
        public @ResponseBody String testCors() {
            return "whatever";
        }
    }
}

请注意,当我实际使用此配置运行 SpringBoot 应用程序时,我们确实获得了 CORS 标头。

任何帮助表示赞赏。

spring-mvc spring-boot testing cors
6个回答
37
投票

CORS 请求需要包含

Origin
标头,以便服务器处理它。模拟 GET 请求没有此标头。 API 确实允许我们在模拟请求中包含标头。

公共 MockHttpServletRequestBuilder 标头(字符串名称, 对象...值)

向请求添加标头。值总是被添加。 参数: name - 标题名称 值 - 一个或多个标头值

这是有效的代码

.perform(options("/test-cors")
    .header("Access-Control-Request-Method", "GET")
    .header("Origin", "http://www.someurl.com"))

两个标头都是必需的,并且

configuration
要求允许的来源和方法与测试中传递的值一致。


1
投票

无需初始化 CorsConfigurationSource Bean,只需直接初始化 CorsFilter。只需像这样改变该方法并尝试即可,

@Bean
public CorsFilter corsFilter() {
        CorsConfiguration configuration = new CorsConfiguration();
        List<String> allowedMethods = CORS_ALLOWED_METHODS;
        configuration.setAllowedMethods(allowedMethods);
        configuration.setAllowedOrigins(CORS_ALLOWED_ORIGINS);
        configuration.setAllowedHeaders(CORS_ALLOWED_HEADERS);
        configuration.setAllowCredentials(true);
        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        source.registerCorsConfiguration("/**", configuration);
        return new CorsFilter(source);
}

哈!


0
投票

编写 CORS 设置测试的另一种方法是对预定义的 url 执行模拟请求,然后断言其 MockHttpServletResponse。这是有效的代码 对我来说:

@RunWith(SpringRunner.class)
@SpringBootTest
@AutoConfigureMockMvc
@ActiveProfiles("corsFilterBean")
public class CORSFilterTests {

@Autowired
private MockMvc mvc;

@Test
public void test_corsFilterBean() throws Exception {

    MvcResult result = mvc
            .perform(get("/users/all"))
            .andExpect(status().isOk())
            .andExpect(header().string("Access-Control-Allow-Origin", "*"))
            .andExpect(header().string("Access-Control-Allow-Methods", "POST, GET, PUT, OPTIONS, DELETE"))
            .andExpect(header().string("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept, X-Auth-Token, X-Csrf-Token, WWW-Authenticate, Authorization"))
            .andExpect(header().string("Access-Control-Expose-Headers", "custom-token1, custom-token2"))
            .andExpect(header().string("Access-Control-Allow-Credentials", "false"))
            .andExpect(header().string("Access-Control-Max-Age", "3600"))
            .andDo(print())
            .andReturn();

    MockHttpServletResponse mockResponse = result.getResponse();

    assertThat(mockResponse.getContentType()).contains("application/json;charset=UTF-8");

    Collection<String> responseHeaders = mockResponse.getHeaderNames();
    assertThat(responseHeaders).isNotNull();
    assertThat(1).isEqualTo(1);
    assertThat(responseHeaders.size()).isBetween(5, 15);
  }
}

这假设存在一个支持跨源请求的 CORS 规范类。 这是我的 CORS Filter 类的示例:

public class CORSFilterss extends GenericFilterBean implements Filter {

private Logger logger = LoggerFactory.getLogger(this.getClass());

@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
        throws IOException, ServletException {

    HttpServletResponse httpResponse = (HttpServletResponse) response;
    httpResponse.setHeader("Access-Control-Allow-Origin", "*");
    httpResponse.setHeader("Access-Control-Allow-Methods", "POST, GET, PUT, OPTIONS, DELETE");
    httpResponse.setHeader("Access-Control-Allow-Headers",
            "Origin, X-Requested-With, Content-Type, Accept, X-Auth-Token, X-Csrf-Token, WWW-Authenticate, Authorization");
    httpResponse.setHeader("Access-Control-Expose-Headers", "custom-token1, custom-token2");
    httpResponse.setHeader("Access-Control-Allow-Credentials", "false");
    httpResponse.setHeader("Access-Control-Max-Age", "3600");

    StringBuilder sb = new StringBuilder();
    sb.append("\nCORS HEADERS:\n");
    sb.append("---------------\n");
    httpResponse.getHeaderNames()
            .forEach(name -> {
                        sb.append(name).append(": ").append(httpResponse.getHeader(name)).append("\n");
                    }
            );
    logger.debug("********** CORS Configuration Completed **********");
    logger.debug(sb.toString());

    chain.doFilter(request, response);
  }
} 

此外,Spring Boot 主应用程序类包含一个 FilterRegistrationBean,它注册 CORS 过滤器类。这是我的主要应用程序类的示例:

@SpringBootApplication
public class SpringTestingApplication implements CommandLineRunner {

public static void main(String[] args) {
    SpringApplication.run(SpringTestingApplication.class, args);
}
@Override
public void run(String... args) throws Exception {

}
@Bean
public FilterRegistrationBean corsFilterRegistration() {
    FilterRegistrationBean registrationBean =
            new FilterRegistrationBean(new CORSFilterss());
    registrationBean.setName("CORS FILTER");
    registrationBean.addUrlPatterns("/*");
    registrationBean.setOrder(1);

    return registrationBean;

  }
}

您可以从此 github 演示应用程序获得更多信息


0
投票

这就是我所做的。我使用配置

@Configuration
来使用 Springboot 启用 CORS。这是我的课:

在您的 applicatoin.properties 文件中,您可以添加您的属性和域,如下所示:

allowed.origins=.someurl.com,.otherurl.com,*.someotherurl.com

还有你的配置类:

@配置 @EnableWebMvc 公共类 AppConfig 扩展 WebMvcConfigurerAdapter {

private static final Logger logger = LoggerFactory.getLogger(AppConfig.class);

@Value("#{'${allowed.origins}'.split(',')}")
private List<String> rawOrigins;

@Bean
public RestTemplate restTemplate() {
    return new RestTemplate();
}

@Bean
public WebMvcConfigurer corsConfigurer() {
    return new WebMvcConfigurerAdapter() {
        @Override
        public void addCorsMappings(CorsRegistry registry) {
            logger.info("Adding CORS to the APP");
            registry.addMapping("/**")
                        .allowedOrigins(getOrigin())
                    .allowedMethods(HttpMethod.GET.name(), HttpMethod.POST.name(), HttpMethod.OPTIONS.name())
                    .allowedHeaders(HttpHeaders.AUTHORIZATION, HttpHeaders.CONTENT_TYPE, "accessToken", "CorrelationId", "source")
                    .exposedHeaders(HttpHeaders.AUTHORIZATION, HttpHeaders.CONTENT_TYPE, "accessToken", "CorrelationId", "source")
                    .maxAge(4800);
        }
        /**
         * This is to add Swagger to work when CORS is enabled
         */
        @Override
        public void addResourceHandlers(ResourceHandlerRegistry registry) {

               registry.addResourceHandler("swagger-ui.html")
                        .addResourceLocations("classpath:/META-INF/resources/");

                registry.addResourceHandler("/webjars/**")
                        .addResourceLocations("classpath:/META-INF/resources/webjars/");

        }
    };
}


public String[] getOrigin() {
    int size = rawOrigins.size();
    String[] originArray = new String[size];
    return rawOrigins.toArray(originArray);
}

}

这是我的控制器测试类:

@RunWith(SpringRunner.class)
@WebMvcTest(AuthController.class)
@AutoConfigureMockMvc(secure=false)
@SuppressWarnings("unchecked")
public class AuthControllerTest {

public static final String EXPIRES_IN = "expiresIn";
public static final String TOKEN_TYPE = "tokenType";
public static final String SCOPE = "scope";
public static final String ID_TOKEN = "idToken";
@Autowired
private MockMvc mockMvc;

@MockBean
private AuthService service;

@Mock
private WebMvcConfigurer corsConfigurer;

private static final ObjectMapper objectMapper = new ObjectMapper();

private static final String RESPONSE_JSON = "{\"response\":\"result\"}";

private static final String REDIRECT_URL = "url";

private static final String CODE = "code";

private static final String STATE = "state";

private static final String ACCESS_TOKEN = "accessToken";

private static final Map<String, String> requestHeaders = new HashMap<>();

@Before
public void setup() {
        requestHeaders.put("source", "source");
        requestHeaders.put("CorrelationId", "CorrelationId");
}

/**
* Controller Test to pass the CORS
*/
@Test
public void testGetLoginUrl() throws Exception {
    when(service.getLoginUrl(anyString(),anyMap())).thenReturn(objectMapper.readTree(RESPONSE_JSON));
    this.mockMvc.perform(get("/vendor/auth/loginurl?redirect_url="+ REDIRECT_URL)
            .header("CorrelationId", "1234")
            .header("Origin", "http://localhost:8080"))
            .andDo(print())
            .andExpect(status().isOk())
            .andExpect(jsonPath("$.response", is("result")));

}
}

请注意,在测试类中,我正在嘲笑

WebMvcConfigurer
,它将在内部添加
CORS Registry
并为您的
SpringTest
初始化它。

但是,您需要在标头中传递

Origin
;如果没有它,您将收到来自控制器的 403 - Forbidden 响应。


0
投票

您可以使用 new MockHttpServletRequest() 进行测试:

@Test
    void testCorsConfigurationSource() {
        CorsConfigurationSource source = securityConfig.corsConfigurationSource();
        assertNotNull(source);
        MockHttpServletRequest httpServletRequest = new MockHttpServletRequest();
        httpServletRequest.setContextPath("/");
        httpServletRequest.setRequestURI("/test");
        CorsConfiguration corsConfiguration = source.getCorsConfiguration(httpServletRequest);
        assertNotNull(corsConfiguration);
        assertEquals(ORS_ALLOWED_ORIGINS
        , corsConfiguration.getAllowedOrigins());
    //..
    }

-3
投票

springboot 2.0

import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

@Configuration
@EnableWebMvc
public class CorsConfig implements WebMvcConfigurer {

    @Override
    public void addCorsMappings(CorsRegistry registry) {
        registry.addMapping("/**")
                .allowedOrigins("*")
                .allowCredentials(true)
                .allowedMethods("*")
                .maxAge(3600);
    }

@CrossOrigin(origins="http://localhost:9000", maxAge=3600)
@RestController
public class RestController {}

@CrossOrigin(origins="http://localhost:9000")
@GetMapping("/hello")
public Greeting greeting() {
    return "world";
}

© www.soinside.com 2019 - 2024. All rights reserved.