我正在尝试使用 Spring Security 和 Spring Boot 在资源之间进行构建和服务。 我的地图如下:LandingPage (VM1) -> API 服务 (SpringApp) -> 带数据的资源服务 (VM_N) 我在浏览器中面临 CORS 问题,而通过 POSTMAN 的 API 调用工作正常。 我知道 POSTMAN 不关心 CORS,因此问题仅存在于浏览器中。 这是我在 SA(Spring 应用程序)上的安全配置:
@Configuration
@EnableWebSecurity
@EnableMethodSecurity
@RequiredArgsConstructor
public class SecurityConfig {
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
LOGGER.info("securityFilterChain ");
http
.csrf(Customizer.withDefaults())
// .addFilterBefore(corsFilter(), CorsFilter.class)
.httpBasic(Customizer.withDefaults())
.formLogin(Customizer.withDefaults())
// .cors((cors) -> cors
// .configurationSource(corsConfigurationSource()))
.authorizeRequests(authorize -> authorize
.requestMatchers()
.requestMatchers(CorsUtils::isPreFlightRequest).permitAll()
.requestMatchers(HttpMethod.OPTIONS).permitAll()
.requestMatchers("/info/**").permitAll()
.requestMatchers("/register/**").permitAll()
.anyRequest().authenticated()
)
.oauth2ResourceServer(oAuth -> oAuth.jwt(jwt -> {
jwt.decoder(jwtDecoder());
jwt.jwtAuthenticationConverter(jwtAuthConverter);
}))
.sessionManagement(session -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS));
return http.build();
}
@Bean
public CorsFilter corsFilter() {
CorsFilter corsFilter = new CorsFilter(corsConfigurationSource());
return corsFilter;
}
@Bean
public CorsConfigurationSource corsConfigurationSource() {
LOGGER.info("CORS config load");
CorsConfiguration configuration = new CorsConfiguration();
configuration.addAllowedOriginPattern(landing); // Landing VM
configuration.addAllowedHeader("Authorization, Origin, X-Requested-With, Content-Type, Accept, " +
"Access-Control-Allow-Headers, Access-Control-Request-Method, Access-Control-Request-Headers");
configuration.addAllowedMethod("HEAD, GET, PUT, POST, OPTIONS");
configuration.addExposedHeader("Authorization");
configuration.setAllowCredentials(true);
CorsConfiguration publicEndpointConfig = new CorsConfiguration();
publicEndpointConfig.addAllowedOriginPattern(landing); // Landing VM
publicEndpointConfig.addAllowedOriginPattern(gateway); // Gateway VM
publicEndpointConfig.addAllowedOriginPattern(php); // PHP VM
publicEndpointConfig.addAllowedHeader("Authorization, Origin, X-Requested-With, Content-Type, Accept");
publicEndpointConfig.addAllowedMethod("HEAD, GET, PUT, POST, OPTIONS");
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/info/**", publicEndpointConfig);
source.registerCorsConfiguration("/register/**", publicEndpointConfig);
source.registerCorsConfiguration("/**", configuration);
return source;
}
}
如您所见,我已经注释掉了 addFilterBefore 和 cors(),因为它们似乎对应用程序没有任何影响。
我的控制器如下:
@RequestMapping(value = "**", method = RequestMethod.OPTIONS)
@CrossOrigin(origins = landing)
public ResponseEntity<String> handleOptions() {
LOGGER.info("INFO handle general OPTIONS requests");
HttpHeaders headers = new HttpHeaders();
headers.add("Access-Control-Allow-Origin", landing );
headers.add("Access-Control-Allow-Methods", "HEAD, GET, POST, PUT, OPTIONS, DELETE");
headers.add("Access-Control-Allow-Credentials", "true");
headers.add("Access-Control-Allow-Headers", "Authorization, Origin, X-Requested-With, Content-Type, Accept");
headers.add("Access-Control-Max-Age", "3600");
return ResponseEntity.ok().headers(headers).body("handle OPTIONS requests");
}
@RequestMapping(value = "**", method = RequestMethod.GET)
@CrossOrigin(origins = landing)
public ResponseEntity<String> getAnythingElse(Authentication authentication, HttpServletRequest request) {
LOGGER.info("user with no authority or role, getAnythingElse");
String tokenValue = null;
String phpUri = null;
LOGGER.debug("Authentication is: " + authentication);
if (authentication != null && authentication.isAuthenticated()) {
JwtAuthenticationToken jwtAuthenticationToken = (JwtAuthenticationToken) authentication;
Jwt jwt = jwtAuthenticationToken.getToken();
tokenValue = jwt.getTokenValue();
LOGGER.debug("Token is: " + tokenValue);
}
String requestUrl = request.getRequestURL().toString();
LOGGER.info("Request: " + requestUrl);
String regexPattern = ".com/(.*)";
Pattern pattern = Pattern.compile(regexPattern);
Matcher matcher = pattern.matcher(requestUrl);
if (matcher.find()) {
phpUri = matcher.group(1);
}
// Create HttpHeaders and add the token to the request header
HttpHeaders headers = new HttpHeaders();
headers.add("Access-Control-Allow-Origin", landing );
headers.add("Access-Control-Allow-Methods", "HEAD, GET, POST, PUT, OPTIONS");
headers.add("Access-Control-Allow-Credentials", "true");
headers.add("Access-Control-Allow-Headers", "Authorization, Origin, X-Requested-With, Content-Type, Accept");
headers.add("Access-Control-Max-Age", "3600");
headers.set("Authorization", "Bearer " + tokenValue);
// Create an HttpEntity with the headers
HttpEntity<String> entity = new HttpEntity<>(headers);
// Create a RestTemplate
RestTemplate restTemplate = new RestTemplate();
LOGGER.info("Full URL: " + (phpApiUrl + phpUri));
// Make the HTTP request to the PHP API using exchange method
ResponseEntity<String> response = restTemplate.exchange(
phpApiUrl + phpUri, // PHP API URL
HttpMethod.GET, // HTTP method
entity, // HttpEntity with headers
String.class // Response type
);
// Get and return the response body
return ResponseEntity.ok().contentType(MediaType.APPLICATION_JSON).body(response.getBody());
}
但是,使用所有这些配置我仍然遇到错误:
跨源请求被阻止:同源策略不允许读取 远程资源位于 https://springApp/login/user_info •(原因: CORS 请求未成功)。状态代码:(空)。块引用
跨源请求被阻止:同源策略不允许读取 远程资源位于 https://springApp/issue_tracker/?格式=json. (原因:根据 header 不允许 header 'cache-control' 来自 CORS 预检响应的“Access-Control-Allow-Headers”)。
根据 Spring 文档,这个配置应该足以工作,但它显然不起作用。
任何人都可以向我解释这个配置有什么问题或者指出我错过了什么吗?
谢谢
您可以将
configuration.addAllowedOriginPattern(landing);
更改为 configuration.addAllowedOriginPattern("*"); //will accept request from all origins
或者您可以指定列表(如果来源/域如 List<String> domains = Arrays.asList("https://localhost:8080", "https://google.com")
)