我正在尝试编写一个测试来验证我们的 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 标头。
任何帮助表示赞赏。
CORS 请求需要包含
Origin
标头,以便服务器处理它。模拟 GET 请求没有此标头。 API 确实允许我们在模拟请求中包含标头。
公共 MockHttpServletRequestBuilder 标头(字符串名称, 对象...值)
向请求添加标头。值总是被添加。 参数: name - 标题名称 值 - 一个或多个标头值
这是有效的代码
.perform(options("/test-cors")
.header("Access-Control-Request-Method", "GET")
.header("Origin", "http://www.someurl.com"))
两个标头都是必需的,并且
configuration
要求允许的来源和方法与测试中传递的值一致。
无需初始化 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);
}
哈!
编写 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 演示应用程序获得更多信息
这就是我所做的。我使用配置
@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 响应。
您可以使用 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());
//..
}
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";
}