spring-boot 和 angularjs 的 CORS 不工作
CORS with spring-boot and angularjs not working
我正在尝试从一个应用程序(spring-启动应用程序)上调用另一个应用程序(angularjs)上的 REST 端点。这些应用程序 运行 在以下主机和端口上。
- REST 应用程序,使用 spring 引导,
http://localhost:8080
- HTML 申请,使用 angularjs,
http://localhost:50029
我也在使用 spring-security
和 spring-boot 应用程序。从 HTML 应用程序,我可以向 REST 应用程序进行身份验证,但是此后,我仍然无法访问任何 REST 端点。例如,我有一个 angularjs 服务定义如下。
adminServices.factory('AdminService', ['$resource', '$http', 'conf', function($resource, $http, conf) {
var s = {};
s.isAdminLoggedIn = function(data) {
return $http({
method: 'GET',
url: 'http://localhost:8080/api/admin/isloggedin',
withCredentials: true,
headers: {
'X-Requested-With': 'XMLHttpRequest'
}
});
};
s.login = function(username, password) {
var u = 'username=' + encodeURI(username);
var p = 'password=' + encodeURI(password);
var r = 'remember_me=1';
var data = u + '&' + p + '&' + r;
return $http({
method: 'POST',
url: 'http://localhost:8080/login',
data: data,
headers: {'Content-Type': 'application/x-www-form-urlencoded'}
});
};
return s;
}]);
angularjs 控制器如下所示。
adminControllers.controller('LoginController', ['$scope', '$http', 'AdminService', function($scope, $http, AdminService) {
$scope.username = '';
$scope.password = '';
$scope.signIn = function() {
AdminService.login($scope.username, $scope.password)
.success(function(d,s) {
if(d['success']) {
console.log('ok authenticated, call another REST endpoint');
AdminService.isAdminLoggedIn()
.success(function(d,s) {
console.log('i can access a protected REST endpoint after logging in');
})
.error(function(d, s) {
console.log('huh, error checking to see if admin is logged in');
$scope.reset();
});
} else {
console.log('bad credentials?');
}
})
.error(function(d, s) {
console.log('huh, error happened!');
});
};
}]);
在调用 http://localhost:8080/api/admin/isloggedin
时,我收到 401 Unauthorized
。
在 REST 应用程序端,我有一个如下所示的 CORS 过滤器。
@Component
@Order(Ordered.HIGHEST_PRECEDENCE)
public class CORSFilter implements Filter {
@Override
public void destroy() { }
@Override
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain)
throws IOException, ServletException {
HttpServletResponse response = (HttpServletResponse) res;
HttpServletRequest request = (HttpServletRequest) req;
response.setHeader("Access-Control-Allow-Origin", "http://localhost:50029");
response.setHeader("Access-Control-Allow-Methods", "POST, PUT, GET, OPTIONS, DELETE");
response.setHeader("Access-Control-Max-Age", "3600");
response.setHeader("Access-Control-Allow-Headers", "X-Requested-With, X-Auth-Token");
response.setHeader("Access-Control-Allow-Credentials", "true");
if(!"OPTIONS".equalsIgnoreCase(request.getMethod())) {
chain.doFilter(req, res);
}
}
@Override
public void init(FilterConfig config) throws ServletException { }
}
我的 spring 安全配置如下所示。
@Configuration
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
private RestAuthenticationEntryPoint restAuthenticationEntryPoint;
@Autowired
private JsonAuthSuccessHandler jsonAuthSuccessHandler;
@Autowired
private JsonAuthFailureHandler jsonAuthFailureHandler;
@Autowired
private JsonLogoutSuccessHandler jsonLogoutSuccessHandler;
@Autowired
private AuthenticationProvider authenticationProvider;
@Autowired
private UserDetailsService userDetailsService;
@Autowired
private PersistentTokenRepository persistentTokenRepository;
@Value("${rememberme.key}")
private String rememberMeKey;
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.csrf().disable()
.exceptionHandling()
.authenticationEntryPoint(restAuthenticationEntryPoint)
.and()
.authorizeRequests()
.antMatchers("/api/admin/**").hasRole("ADMIN")
.antMatchers("/", "/admin", "/css/**", "/js/**", "/fonts/**", "/api/**").permitAll()
.anyRequest().authenticated()
.and()
.formLogin()
.successHandler(jsonAuthSuccessHandler)
.failureHandler(jsonAuthFailureHandler)
.permitAll()
.and()
.logout()
.deleteCookies("remember-me", "JSESSIONID")
.logoutSuccessHandler(jsonLogoutSuccessHandler)
.permitAll()
.and()
.rememberMe()
.userDetailsService(userDetailsService)
.tokenRepository(persistentTokenRepository)
.rememberMeCookieName("REMEMBER_ME")
.rememberMeParameter("remember_me")
.tokenValiditySeconds(1209600)
.useSecureCookie(false)
.key(rememberMeKey);
}
@Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth
.authenticationProvider(authenticationProvider);
}
}
所有处理程序正在做的是根据用户是否登录、身份验证失败或注销写出 JSON 响应,如 {success: true}
。 RestAuthenticationEntryPoint
如下所示。
@Component
public class RestAuthenticationEntryPoint implements AuthenticationEntryPoint {
@Override
public void commence(HttpServletRequest req, HttpServletResponse resp, AuthenticationException ex)
throws IOException, ServletException {
resp.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Unauthorized");
}
}
关于我遗漏或做错了什么的任何想法?
import java.io.IOException;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
@Component
public class SimpleCORSFilter implements Filter {
private final Logger log = LoggerFactory.getLogger(SimpleCORSFilter.class);
public SimpleCORSFilter() {
log.info("SimpleCORSFilter init");
}
@Override
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) req;
HttpServletResponse response = (HttpServletResponse) res;
response.setHeader("Access-Control-Allow-Origin", request.getHeader("Origin"));
response.setHeader("Access-Control-Allow-Credentials", "true");
response.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE");
response.setHeader("Access-Control-Max-Age", "3600");
response.setHeader("Access-Control-Allow-Headers", "Content-Type, Accept, X-Requested-With, remember-me");
chain.doFilter(req, res);
}
@Override
public void init(FilterConfig filterConfig) {
}
@Override
public void destroy() {
}
}
无需额外定义此过滤器,只需添加此 class。 Spring将为您扫描并添加。简单的 CORS 过滤器。
这是示例:spring-enable-cors
我也遇到过类似情况。经过研究和测试,这是我的发现:
使用 Spring 引导,启用全局 CORS 的推荐方法是在 Spring MVC 中声明并结合细粒度 @CrossOrigin
配置:
@Configuration
public class CorsConfig {
@Bean
public WebMvcConfigurer corsConfigurer() {
return new WebMvcConfigurerAdapter() {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**").allowedMethods("GET", "POST", "PUT", "DELETE").allowedOrigins("*")
.allowedHeaders("*");
}
};
}
}
现在,由于您正在使用 Spring 安全性,因此您还必须在 Spring 安全级别启用 CORS,以允许它利用在 Spring 定义的配置=] MVC 级别为:
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http.cors().and()...
}
}
Here 是解释 Spring MVC 框架中 CORS 支持的非常优秀的教程。
检查这个:
@Override
protected void configure(HttpSecurity httpSecurity) throws Exception {
...
.antMatchers(HttpMethod.OPTIONS, "/**").permitAll()
...
}
这对我有用:
@Configuration
public class MyConfig extends WebSecurityConfigurerAdapter {
//...
@Override
protected void configure(HttpSecurity http) throws Exception {
//...
http.cors().configurationSource(new CorsConfigurationSource() {
@Override
public CorsConfiguration getCorsConfiguration(HttpServletRequest request) {
CorsConfiguration config = new CorsConfiguration();
config.setAllowedHeaders(Collections.singletonList("*"));
config.setAllowedMethods(Collections.singletonList("*"));
config.addAllowedOrigin("*");
config.setAllowCredentials(true);
return config;
}
});
//...
}
//...
}
扩展 WebSecurityConfigurerAdapter class 并覆盖 @EnableWebSecurity class 中的 configure() 方法会起作用:下面是示例 class
@Override
protected void configure(final HttpSecurity http) throws Exception {
http
.csrf().disable()
.exceptionHandling();
http.headers().cacheControl();
@Override
public CorsConfiguration getCorsConfiguration(final HttpServletRequest request) {
return new CorsConfiguration().applyPermitDefaultValues();
}
});
}
}
如果您的程序最初不使用 spring 安全性并且无法承担代码更改的费用,那么创建一个简单的反向代理就可以解决问题。就我而言,我使用了具有以下配置的 Nginx:
http {
server {
listen 9090;
location / {
if ($request_method = 'OPTIONS') {
add_header 'Access-Control-Allow-Origin' '*';
add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
#
# Custom headers and headers various browsers *should* be OK with but aren't
#
add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range';
#
# Tell client that this pre-flight info is valid for 20 days
#
add_header 'Access-Control-Max-Age' 1728000;
add_header 'Content-Type' 'text/plain; charset=utf-8';
add_header 'Content-Length' 0;
return 204;
}
if ($request_method = 'POST') {
add_header 'Access-Control-Allow-Origin' '*';
add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range';
add_header 'Access-Control-Expose-Headers' 'Content-Length,Content-Range';
}
if ($request_method = 'GET') {
add_header 'Access-Control-Allow-Origin' '*';
add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range';
add_header 'Access-Control-Expose-Headers' 'Content-Length,Content-Range';
}
proxy_pass http://localhost:8080;
}
}
}
我的程序监听 :8080.
REF: CORS on Nginx
对我来说,当使用 spring 安全性时,唯一 100% 有效的方法是跳过所有额外的过滤器和 bean 以及任何间接的 "magic" 人们一直建议对他们有用的东西但不适合我。
而是强制它用普通的 StaticHeadersWriter
:
编写您需要的 headers
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http
// your security config here
.authorizeRequests()
.antMatchers(HttpMethod.TRACE, "/**").denyAll()
.antMatchers("/admin/**").authenticated()
.anyRequest().permitAll()
.and().httpBasic()
.and().headers().frameOptions().disable()
.and().csrf().disable()
.headers()
// the headers you want here. This solved all my CORS problems!
.addHeaderWriter(new StaticHeadersWriter("Access-Control-Allow-Origin", "*"))
.addHeaderWriter(new StaticHeadersWriter("Access-Control-Allow-Methods", "POST, GET"))
.addHeaderWriter(new StaticHeadersWriter("Access-Control-Max-Age", "3600"))
.addHeaderWriter(new StaticHeadersWriter("Access-Control-Allow-Credentials", "true"))
.addHeaderWriter(new StaticHeadersWriter("Access-Control-Allow-Headers", "Origin,Accept,X-Requested-With,Content-Type,Access-Control-Request-Method,Access-Control-Request-Headers,Authorization"));
}
}
这是我发现的最直接、最明确的方法。希望对大家有帮助。
如果您想在不使用过滤器或不使用配置文件的情况下启用 CORS,只需添加
@CrossOrigin
到控制器的顶部,它就可以工作了。
如果您有 Spring 具有 Spring 安全性的 Spring 启动 REST 服务应用程序(不是 Spring MVC),则以上述其他答案为基础,然后通过 [=41] 启用 CORS =] 安全性就足够了(如果您使用 Spring MVC,那么使用 Yogen 提到的 WebMvcConfigurer
bean 可能是可行的方法,因为 Spring 安全性将委托给其中提到的 CORS 定义)
所以您需要一个执行以下操作的安全配置:
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
//other http security config
http.cors().configurationSource(corsConfigurationSource());
}
//This can be customized as required
CorsConfigurationSource corsConfigurationSource() {
CorsConfiguration configuration = new CorsConfiguration();
List<String> allowOrigins = Arrays.asList("*");
configuration.setAllowedOrigins(allowOrigins);
configuration.setAllowedMethods(singletonList("*"));
configuration.setAllowedHeaders(singletonList("*"));
//in case authentication is enabled this flag MUST be set, otherwise CORS requests will fail
configuration.setAllowCredentials(true);
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", configuration);
return source;
}
}
此 link 有更多关于相同内容的信息:https://docs.spring.io/spring-security/site/docs/current/reference/htmlsingle/#cors
注:
- 为产品部署的应用程序的所有来源 (*) 启用 CORS 可能并不总是一个好主意。
- CSRF 可以通过 Spring HttpSecurity 自定义启用,没有任何问题
- 如果您在应用程序中使用 Spring 启用了身份验证(例如通过
UserDetailsService
),则必须添加 configuration.setAllowCredentials(true);
针对 Spring 启动 2.0.0.RELEASE 进行了测试(即 Spring 5.0.4.RELEASE 和 Spring 安全 5.0.3.RELEASE)
我正在使用 spring boot 2.1.0
,对我有用的是
一个。通过以下方式添加 cors 映射:
@Configuration
public class Config implements WebMvcConfigurer {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**").allowedOrigins("*");
}
}
乙。为 spring security
添加以下配置到我的 HttpSecurity
.cors().configurationSource(new CorsConfigurationSource() {
@Override
public CorsConfiguration getCorsConfiguration(HttpServletRequest request) {
CorsConfiguration config = new CorsConfiguration();
config.setAllowedHeaders(Collections.singletonList("*"));
config.setAllowedMethods(Collections.singletonList("*"));
config.addAllowedOrigin("*");
config.setAllowCredentials(true);
return config;
}
})
此外,在 Zuul 代理的情况下,您可以使用此 INSTEAD OF A 和 B(只需使用 HttpSecurity.cors()
在 Spring 安全性中启用它) :
@Bean
public CorsFilter corsFilter() {
final UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
final CorsConfiguration config = new CorsConfiguration();
config.setAllowCredentials(true);
config.addAllowedOrigin("*");
config.addAllowedHeader("*");
config.addAllowedMethod("OPTIONS");
config.addAllowedMethod("HEAD");
config.addAllowedMethod("GET");
config.addAllowedMethod("PUT");
config.addAllowedMethod("POST");
config.addAllowedMethod("DELETE");
config.addAllowedMethod("PATCH");
source.registerCorsConfiguration("/**", config);
return new CorsFilter(source);
}
这对我有用。
@EnableWebSecurity
public class WebSecurityConfiguration extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http.cors();
}
}
@Configuration
public class WebConfiguration implements WebMvcConfigurer {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry
.addMapping("/**")
.allowedMethods("*")
.allowedHeaders("*")
.allowedOrigins("*")
.allowCredentials(true);
}
}
此答案复制了@abosancic 的答案,但增加了额外的安全性以避免 CORS 利用。
提示 1:不要在未检查允许访问的主机列表的情况下按原样反映传入的 Origin。
提示 2:仅允许白名单主机的凭据请求。
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
@Component
public class SimpleCORSFilter implements Filter {
private final Logger log = LoggerFactory.getLogger(SimpleCORSFilter.class);
private List<String> allowedOrigins;
public SimpleCORSFilter() {
log.info("SimpleCORSFilter init");
allowedOrigins = new ArrayList<>();
allowedOrigins.add("https://mysafeorigin.com");
allowedOrigins.add("https://itrustthissite.com");
}
@Override
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) req;
HttpServletResponse response = (HttpServletResponse) res;
String allowedOrigin = getOriginToAllow(request.getHeader("Origin"));
if(allowedOrigin != null) {
response.setHeader("Access-Control-Allow-Origin", allowedOrigin);
response.setHeader("Access-Control-Allow-Credentials", "true");
}
response.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE");
response.setHeader("Access-Control-Max-Age", "3600");
response.setHeader("Access-Control-Allow-Headers", "Content-Type, Accept, X-Requested-With, remember-me");
chain.doFilter(req, res);
}
@Override
public void init(FilterConfig filterConfig) {
}
@Override
public void destroy() {
}
public String getOriginToAllow(String incomingOrigin) {
if(allowedOrigins.contains(incomingOrigin.toLowerCase())) {
return incomingOrigin;
} else {
return null;
}
}
}
步骤 1
通过使用 @CrossOrigin
注释对控制器进行注释将允许 CORS 配置。
@CrossOrigin
@RestController
public class SampleController {
.....
}
步骤 2
Spring 已经有一个 CorsFilter,尽管您可以将自己的 CorsFilter 注册为 bean 以提供您自己的配置,如下所示。
@Bean
public CorsFilter corsFilter() {
final UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
final CorsConfiguration config = new CorsConfiguration();
config.setAllowedOrigins(Collections.singletonList("http://localhost:3000")); // Provide list of origins if you want multiple origins
config.setAllowedHeaders(Arrays.asList("Origin", "Content-Type", "Accept"));
config.setAllowedMethods(Arrays.asList("GET", "POST", "PUT", "OPTIONS", "DELETE", "PATCH"));
config.setAllowCredentials(true);
source.registerCorsConfiguration("/**", config);
return new CorsFilter(source);
}
在我们的 Spring 启动应用程序中,我们已经像这样设置了 CorsConfigurationSource。
先添加allowedOrigns
然后设置applyPermitDefaultValues()
的顺序让Spring为允许的headers设置默认值,暴露headers,允许的方法,等等,所以我们不必指定这些。
public CorsConfigurationSource corsConfigurationSource() {
CorsConfiguration configuration = new CorsConfiguration();
configuration.setAllowedOrigins(Arrays.asList("http://localhost:8084"));
configuration.applyPermitDefaultValues();
UrlBasedCorsConfigurationSource configurationSource = new UrlBasedCorsConfigurationSource();
configurationSource.registerCorsConfiguration("/**", configuration);
return configurationSource;
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/api/**")
.access("@authProvider.validateApiKey(request)")
.anyRequest().authenticated()
.and().cors()
.and().csrf().disable()
.httpBasic().authenticationEntryPoint(authenticationEntryPoint);
http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
}
做一个单class就好了,这样就好了:
@Component
@Order(Ordered.HIGHEST_PRECEDENCE)
public class MyCorsConfig implements Filter {
@Override
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
final HttpServletResponse response = (HttpServletResponse) res;
response.setHeader("Access-Control-Allow-Origin", "*");
response.setHeader("Access-Control-Allow-Methods", "POST, PUT, GET, OPTIONS, DELETE");
response.setHeader("Access-Control-Allow-Headers", "Authorization, Content-Type, enctype");
response.setHeader("Access-Control-Max-Age", "3600");
if (HttpMethod.OPTIONS.name().equalsIgnoreCase(((HttpServletRequest) req).getMethod())) {
response.setStatus(HttpServletResponse.SC_OK);
} else {
chain.doFilter(req, res);
}
}
@Override
public void destroy() {
}
@Override
public void init(FilterConfig config) throws ServletException {
}
}
这对我有用,可以在 Spring 启动和 React
之间禁用 CORS
@Configuration
public class CorsConfig implements WebMvcConfigurer {
/**
* Overriding the CORS configuration to exposed required header for ussd to work
*
* @param registry CorsRegistry
*/
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
.allowedOrigins("*")
.allowedMethods("*")
.allowedHeaders("*")
.allowCredentials(true)
.maxAge(4800);
}
}
我必须像下面一样修改安全配置:
@Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable()
.cors().configurationSource(new CorsConfigurationSource() {
@Override
public CorsConfiguration getCorsConfiguration(HttpServletRequest request) {
CorsConfiguration config = new CorsConfiguration();
config.setAllowedHeaders(Collections.singletonList("*"));
config.setAllowedMethods(Collections.singletonList("*"));
config.addAllowedOrigin("*");
config.setAllowCredentials(true);
return config;
}
}).and()
.antMatcher("/api/**")
.authorizeRequests()
.anyRequest().authenticated()
.and().httpBasic()
.and().sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and().exceptionHandling().accessDeniedHandler(apiAccessDeniedHandler());
}
我很惊讶只发现 Eduardo Dennis 指出了最新的解决方案,它更简单并且不需要编写您自己的过滤器 classes:它使用
org.springframework.web.bind.annotation.CrossOrigin
控制器上的注释
- 并将
and().cors()
添加到您的 Spring 安全配置中。
这就是您要做的全部!
您可以像这样使用 @CrossOrigin
注释:
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller
@RequestMapping("/api")
@CrossOrigin
public class BackendController {
...
}
如果要配置 allowedHeaders
、methods
、origins
等,只需将这些值添加到注释中,如下所示:@CrossOrigin(origins = "http://localhost:50029", maxAge = 3600)
.
使用@CrossOrigin
注解,Spring安全配置变得异常简单。只需将 and().cors()
添加到您的 WebSecurityConfig.java
class:
@Configuration
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.csrf().disable()
.and().cors()
...
}
就是这样!您可以删除您的 Filter/CORSFilter classes。如果你想添加一个全局配置,你也可以声明一个 CorsConfigurationSource
。参见 this great answer or this blog post by Sébastien Deleuze)。 Spring 开发人员也明确表示:
This approach supersedes the filter-based approach previously
recommended.
因此,接受的答案已过时。这也是一个完整的示例项目:https://github.com/jonashackt/microservice-api-spring-boot
要在全球启用 CORS,您需要在两个地方进行更改:
1. Spring开机:
@Configuration
public class CorsConfiguration extends WebMvcConfigurationSupport {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**").allowedOrigins("*").allowedMethods("*")
.allowCredentials(true);
}
}
您可以在 WebMvcConfigurerAdapter
中执行相同的操作,或者创建 WebMvcConfigurer
的 bean。
2。 Spring 安全性
@Override
protected void configure(HttpSecurity http) throws Exception {
http.cors().and()
.authorizeRequests()
.antMatchers(HttpMethod.OPTIONS).permitAll() //Permits your preflight request
}
在 Spring Boot 2.3 上工作。3.RELEASE
简单的方法是在 spring 引导应用程序 class(class 和 @SpringBootApplication)中创建一个 bean,如下所示:
注意!我在下面的“setAllowedOrigins()”中指定了“http://localhost:4200”,因为 运行 本地主机上的应用程序并使用 angular 默认端口。
@Bean
public CorsFilter corsFilter(){
CorsConfiguration corsConfiguration = new CorsConfiguration();
corsConfiguration.setAllowCredentials(true);
corsConfiguration.setAllowedOrigins(Arrays.asList("http://localhost:4200"));
corsConfiguration.setAllowedHeaders(Arrays.asList("Origin","Access-Control-Allow-Origin","Content-Type",
"Accept", "Authorization", "Origin, Accept", "X-Requested-With",
"Access-Control-Request-Method", "Access-Control-Request-Headers"));
corsConfiguration.setExposedHeaders(Arrays.asList("Origin", "Content-Type", "Accept","Authorization",
"Access-Control-Allow-Origin", "Access-Control-Allow-Origin", "Access-Control-Allow-Credentials"));
corsConfiguration.setAllowedMethods(Arrays.asList("GET", "POST","PUT","DELETE","OPTIONS"));
UrlBasedCorsConfigurationSource urlBasedCorsConfigurationSource = new UrlBasedCorsConfigurationSource();
urlBasedCorsConfigurationSource.registerCorsConfiguration("/**", corsConfiguration);
return new CorsFilter(urlBasedCorsConfigurationSource);
}
您可以在 sprıng boot
中的每个 restController class 上使用此注释
@CrossOrigin("*")
如果您正在使用 spring 安全性,您需要在任何具有扩展 extends WebSecurityConfigurerAdapter
的 class 上使用它
@Bean
CorsConfigurationSource corsConfigurationSource() {
CorsConfiguration configuration = new CorsConfiguration();
configuration.setAllowedOrigins(Arrays.asList("https://example.com"));
configuration.setAllowedMethods(Arrays.asList("GET","POST"));
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", configuration);
return source;
}
我正在尝试从一个应用程序(spring-启动应用程序)上调用另一个应用程序(angularjs)上的 REST 端点。这些应用程序 运行 在以下主机和端口上。
- REST 应用程序,使用 spring 引导,
http://localhost:8080
- HTML 申请,使用 angularjs,
http://localhost:50029
我也在使用 spring-security
和 spring-boot 应用程序。从 HTML 应用程序,我可以向 REST 应用程序进行身份验证,但是此后,我仍然无法访问任何 REST 端点。例如,我有一个 angularjs 服务定义如下。
adminServices.factory('AdminService', ['$resource', '$http', 'conf', function($resource, $http, conf) {
var s = {};
s.isAdminLoggedIn = function(data) {
return $http({
method: 'GET',
url: 'http://localhost:8080/api/admin/isloggedin',
withCredentials: true,
headers: {
'X-Requested-With': 'XMLHttpRequest'
}
});
};
s.login = function(username, password) {
var u = 'username=' + encodeURI(username);
var p = 'password=' + encodeURI(password);
var r = 'remember_me=1';
var data = u + '&' + p + '&' + r;
return $http({
method: 'POST',
url: 'http://localhost:8080/login',
data: data,
headers: {'Content-Type': 'application/x-www-form-urlencoded'}
});
};
return s;
}]);
angularjs 控制器如下所示。
adminControllers.controller('LoginController', ['$scope', '$http', 'AdminService', function($scope, $http, AdminService) {
$scope.username = '';
$scope.password = '';
$scope.signIn = function() {
AdminService.login($scope.username, $scope.password)
.success(function(d,s) {
if(d['success']) {
console.log('ok authenticated, call another REST endpoint');
AdminService.isAdminLoggedIn()
.success(function(d,s) {
console.log('i can access a protected REST endpoint after logging in');
})
.error(function(d, s) {
console.log('huh, error checking to see if admin is logged in');
$scope.reset();
});
} else {
console.log('bad credentials?');
}
})
.error(function(d, s) {
console.log('huh, error happened!');
});
};
}]);
在调用 http://localhost:8080/api/admin/isloggedin
时,我收到 401 Unauthorized
。
在 REST 应用程序端,我有一个如下所示的 CORS 过滤器。
@Component
@Order(Ordered.HIGHEST_PRECEDENCE)
public class CORSFilter implements Filter {
@Override
public void destroy() { }
@Override
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain)
throws IOException, ServletException {
HttpServletResponse response = (HttpServletResponse) res;
HttpServletRequest request = (HttpServletRequest) req;
response.setHeader("Access-Control-Allow-Origin", "http://localhost:50029");
response.setHeader("Access-Control-Allow-Methods", "POST, PUT, GET, OPTIONS, DELETE");
response.setHeader("Access-Control-Max-Age", "3600");
response.setHeader("Access-Control-Allow-Headers", "X-Requested-With, X-Auth-Token");
response.setHeader("Access-Control-Allow-Credentials", "true");
if(!"OPTIONS".equalsIgnoreCase(request.getMethod())) {
chain.doFilter(req, res);
}
}
@Override
public void init(FilterConfig config) throws ServletException { }
}
我的 spring 安全配置如下所示。
@Configuration
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
private RestAuthenticationEntryPoint restAuthenticationEntryPoint;
@Autowired
private JsonAuthSuccessHandler jsonAuthSuccessHandler;
@Autowired
private JsonAuthFailureHandler jsonAuthFailureHandler;
@Autowired
private JsonLogoutSuccessHandler jsonLogoutSuccessHandler;
@Autowired
private AuthenticationProvider authenticationProvider;
@Autowired
private UserDetailsService userDetailsService;
@Autowired
private PersistentTokenRepository persistentTokenRepository;
@Value("${rememberme.key}")
private String rememberMeKey;
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.csrf().disable()
.exceptionHandling()
.authenticationEntryPoint(restAuthenticationEntryPoint)
.and()
.authorizeRequests()
.antMatchers("/api/admin/**").hasRole("ADMIN")
.antMatchers("/", "/admin", "/css/**", "/js/**", "/fonts/**", "/api/**").permitAll()
.anyRequest().authenticated()
.and()
.formLogin()
.successHandler(jsonAuthSuccessHandler)
.failureHandler(jsonAuthFailureHandler)
.permitAll()
.and()
.logout()
.deleteCookies("remember-me", "JSESSIONID")
.logoutSuccessHandler(jsonLogoutSuccessHandler)
.permitAll()
.and()
.rememberMe()
.userDetailsService(userDetailsService)
.tokenRepository(persistentTokenRepository)
.rememberMeCookieName("REMEMBER_ME")
.rememberMeParameter("remember_me")
.tokenValiditySeconds(1209600)
.useSecureCookie(false)
.key(rememberMeKey);
}
@Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth
.authenticationProvider(authenticationProvider);
}
}
所有处理程序正在做的是根据用户是否登录、身份验证失败或注销写出 JSON 响应,如 {success: true}
。 RestAuthenticationEntryPoint
如下所示。
@Component
public class RestAuthenticationEntryPoint implements AuthenticationEntryPoint {
@Override
public void commence(HttpServletRequest req, HttpServletResponse resp, AuthenticationException ex)
throws IOException, ServletException {
resp.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Unauthorized");
}
}
关于我遗漏或做错了什么的任何想法?
import java.io.IOException;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
@Component
public class SimpleCORSFilter implements Filter {
private final Logger log = LoggerFactory.getLogger(SimpleCORSFilter.class);
public SimpleCORSFilter() {
log.info("SimpleCORSFilter init");
}
@Override
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) req;
HttpServletResponse response = (HttpServletResponse) res;
response.setHeader("Access-Control-Allow-Origin", request.getHeader("Origin"));
response.setHeader("Access-Control-Allow-Credentials", "true");
response.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE");
response.setHeader("Access-Control-Max-Age", "3600");
response.setHeader("Access-Control-Allow-Headers", "Content-Type, Accept, X-Requested-With, remember-me");
chain.doFilter(req, res);
}
@Override
public void init(FilterConfig filterConfig) {
}
@Override
public void destroy() {
}
}
无需额外定义此过滤器,只需添加此 class。 Spring将为您扫描并添加。简单的 CORS 过滤器。 这是示例:spring-enable-cors
我也遇到过类似情况。经过研究和测试,这是我的发现:
使用 Spring 引导,启用全局 CORS 的推荐方法是在 Spring MVC 中声明并结合细粒度
@CrossOrigin
配置:@Configuration public class CorsConfig { @Bean public WebMvcConfigurer corsConfigurer() { return new WebMvcConfigurerAdapter() { @Override public void addCorsMappings(CorsRegistry registry) { registry.addMapping("/**").allowedMethods("GET", "POST", "PUT", "DELETE").allowedOrigins("*") .allowedHeaders("*"); } }; } }
现在,由于您正在使用 Spring 安全性,因此您还必须在 Spring 安全级别启用 CORS,以允许它利用在 Spring 定义的配置=] MVC 级别为:
@EnableWebSecurity public class WebSecurityConfig extends WebSecurityConfigurerAdapter { @Override protected void configure(HttpSecurity http) throws Exception { http.cors().and()... } }
Here 是解释 Spring MVC 框架中 CORS 支持的非常优秀的教程。
检查这个:
@Override
protected void configure(HttpSecurity httpSecurity) throws Exception {
...
.antMatchers(HttpMethod.OPTIONS, "/**").permitAll()
...
}
这对我有用:
@Configuration
public class MyConfig extends WebSecurityConfigurerAdapter {
//...
@Override
protected void configure(HttpSecurity http) throws Exception {
//...
http.cors().configurationSource(new CorsConfigurationSource() {
@Override
public CorsConfiguration getCorsConfiguration(HttpServletRequest request) {
CorsConfiguration config = new CorsConfiguration();
config.setAllowedHeaders(Collections.singletonList("*"));
config.setAllowedMethods(Collections.singletonList("*"));
config.addAllowedOrigin("*");
config.setAllowCredentials(true);
return config;
}
});
//...
}
//...
}
扩展 WebSecurityConfigurerAdapter class 并覆盖 @EnableWebSecurity class 中的 configure() 方法会起作用:下面是示例 class
@Override
protected void configure(final HttpSecurity http) throws Exception {
http
.csrf().disable()
.exceptionHandling();
http.headers().cacheControl();
@Override
public CorsConfiguration getCorsConfiguration(final HttpServletRequest request) {
return new CorsConfiguration().applyPermitDefaultValues();
}
});
}
}
如果您的程序最初不使用 spring 安全性并且无法承担代码更改的费用,那么创建一个简单的反向代理就可以解决问题。就我而言,我使用了具有以下配置的 Nginx:
http {
server {
listen 9090;
location / {
if ($request_method = 'OPTIONS') {
add_header 'Access-Control-Allow-Origin' '*';
add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
#
# Custom headers and headers various browsers *should* be OK with but aren't
#
add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range';
#
# Tell client that this pre-flight info is valid for 20 days
#
add_header 'Access-Control-Max-Age' 1728000;
add_header 'Content-Type' 'text/plain; charset=utf-8';
add_header 'Content-Length' 0;
return 204;
}
if ($request_method = 'POST') {
add_header 'Access-Control-Allow-Origin' '*';
add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range';
add_header 'Access-Control-Expose-Headers' 'Content-Length,Content-Range';
}
if ($request_method = 'GET') {
add_header 'Access-Control-Allow-Origin' '*';
add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range';
add_header 'Access-Control-Expose-Headers' 'Content-Length,Content-Range';
}
proxy_pass http://localhost:8080;
}
}
}
我的程序监听 :8080.
REF: CORS on Nginx
对我来说,当使用 spring 安全性时,唯一 100% 有效的方法是跳过所有额外的过滤器和 bean 以及任何间接的 "magic" 人们一直建议对他们有用的东西但不适合我。
而是强制它用普通的 StaticHeadersWriter
:
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http
// your security config here
.authorizeRequests()
.antMatchers(HttpMethod.TRACE, "/**").denyAll()
.antMatchers("/admin/**").authenticated()
.anyRequest().permitAll()
.and().httpBasic()
.and().headers().frameOptions().disable()
.and().csrf().disable()
.headers()
// the headers you want here. This solved all my CORS problems!
.addHeaderWriter(new StaticHeadersWriter("Access-Control-Allow-Origin", "*"))
.addHeaderWriter(new StaticHeadersWriter("Access-Control-Allow-Methods", "POST, GET"))
.addHeaderWriter(new StaticHeadersWriter("Access-Control-Max-Age", "3600"))
.addHeaderWriter(new StaticHeadersWriter("Access-Control-Allow-Credentials", "true"))
.addHeaderWriter(new StaticHeadersWriter("Access-Control-Allow-Headers", "Origin,Accept,X-Requested-With,Content-Type,Access-Control-Request-Method,Access-Control-Request-Headers,Authorization"));
}
}
这是我发现的最直接、最明确的方法。希望对大家有帮助。
如果您想在不使用过滤器或不使用配置文件的情况下启用 CORS,只需添加
@CrossOrigin
到控制器的顶部,它就可以工作了。
如果您有 Spring 具有 Spring 安全性的 Spring 启动 REST 服务应用程序(不是 Spring MVC),则以上述其他答案为基础,然后通过 [=41] 启用 CORS =] 安全性就足够了(如果您使用 Spring MVC,那么使用 Yogen 提到的 WebMvcConfigurer
bean 可能是可行的方法,因为 Spring 安全性将委托给其中提到的 CORS 定义)
所以您需要一个执行以下操作的安全配置:
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
//other http security config
http.cors().configurationSource(corsConfigurationSource());
}
//This can be customized as required
CorsConfigurationSource corsConfigurationSource() {
CorsConfiguration configuration = new CorsConfiguration();
List<String> allowOrigins = Arrays.asList("*");
configuration.setAllowedOrigins(allowOrigins);
configuration.setAllowedMethods(singletonList("*"));
configuration.setAllowedHeaders(singletonList("*"));
//in case authentication is enabled this flag MUST be set, otherwise CORS requests will fail
configuration.setAllowCredentials(true);
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", configuration);
return source;
}
}
此 link 有更多关于相同内容的信息:https://docs.spring.io/spring-security/site/docs/current/reference/htmlsingle/#cors
注:
- 为产品部署的应用程序的所有来源 (*) 启用 CORS 可能并不总是一个好主意。
- CSRF 可以通过 Spring HttpSecurity 自定义启用,没有任何问题
- 如果您在应用程序中使用 Spring 启用了身份验证(例如通过
UserDetailsService
),则必须添加configuration.setAllowCredentials(true);
针对 Spring 启动 2.0.0.RELEASE 进行了测试(即 Spring 5.0.4.RELEASE 和 Spring 安全 5.0.3.RELEASE)
我正在使用 spring boot 2.1.0
,对我有用的是
一个。通过以下方式添加 cors 映射:
@Configuration
public class Config implements WebMvcConfigurer {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**").allowedOrigins("*");
}
}
乙。为 spring security
添加以下配置到我的HttpSecurity
.cors().configurationSource(new CorsConfigurationSource() {
@Override
public CorsConfiguration getCorsConfiguration(HttpServletRequest request) {
CorsConfiguration config = new CorsConfiguration();
config.setAllowedHeaders(Collections.singletonList("*"));
config.setAllowedMethods(Collections.singletonList("*"));
config.addAllowedOrigin("*");
config.setAllowCredentials(true);
return config;
}
})
此外,在 Zuul 代理的情况下,您可以使用此 INSTEAD OF A 和 B(只需使用 HttpSecurity.cors()
在 Spring 安全性中启用它) :
@Bean
public CorsFilter corsFilter() {
final UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
final CorsConfiguration config = new CorsConfiguration();
config.setAllowCredentials(true);
config.addAllowedOrigin("*");
config.addAllowedHeader("*");
config.addAllowedMethod("OPTIONS");
config.addAllowedMethod("HEAD");
config.addAllowedMethod("GET");
config.addAllowedMethod("PUT");
config.addAllowedMethod("POST");
config.addAllowedMethod("DELETE");
config.addAllowedMethod("PATCH");
source.registerCorsConfiguration("/**", config);
return new CorsFilter(source);
}
这对我有用。
@EnableWebSecurity
public class WebSecurityConfiguration extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http.cors();
}
}
@Configuration
public class WebConfiguration implements WebMvcConfigurer {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry
.addMapping("/**")
.allowedMethods("*")
.allowedHeaders("*")
.allowedOrigins("*")
.allowCredentials(true);
}
}
此答案复制了@abosancic 的答案,但增加了额外的安全性以避免 CORS 利用。
提示 1:不要在未检查允许访问的主机列表的情况下按原样反映传入的 Origin。
提示 2:仅允许白名单主机的凭据请求。
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
@Component
public class SimpleCORSFilter implements Filter {
private final Logger log = LoggerFactory.getLogger(SimpleCORSFilter.class);
private List<String> allowedOrigins;
public SimpleCORSFilter() {
log.info("SimpleCORSFilter init");
allowedOrigins = new ArrayList<>();
allowedOrigins.add("https://mysafeorigin.com");
allowedOrigins.add("https://itrustthissite.com");
}
@Override
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) req;
HttpServletResponse response = (HttpServletResponse) res;
String allowedOrigin = getOriginToAllow(request.getHeader("Origin"));
if(allowedOrigin != null) {
response.setHeader("Access-Control-Allow-Origin", allowedOrigin);
response.setHeader("Access-Control-Allow-Credentials", "true");
}
response.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE");
response.setHeader("Access-Control-Max-Age", "3600");
response.setHeader("Access-Control-Allow-Headers", "Content-Type, Accept, X-Requested-With, remember-me");
chain.doFilter(req, res);
}
@Override
public void init(FilterConfig filterConfig) {
}
@Override
public void destroy() {
}
public String getOriginToAllow(String incomingOrigin) {
if(allowedOrigins.contains(incomingOrigin.toLowerCase())) {
return incomingOrigin;
} else {
return null;
}
}
}
步骤 1
通过使用 @CrossOrigin
注释对控制器进行注释将允许 CORS 配置。
@CrossOrigin
@RestController
public class SampleController {
.....
}
步骤 2
Spring 已经有一个 CorsFilter,尽管您可以将自己的 CorsFilter 注册为 bean 以提供您自己的配置,如下所示。
@Bean
public CorsFilter corsFilter() {
final UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
final CorsConfiguration config = new CorsConfiguration();
config.setAllowedOrigins(Collections.singletonList("http://localhost:3000")); // Provide list of origins if you want multiple origins
config.setAllowedHeaders(Arrays.asList("Origin", "Content-Type", "Accept"));
config.setAllowedMethods(Arrays.asList("GET", "POST", "PUT", "OPTIONS", "DELETE", "PATCH"));
config.setAllowCredentials(true);
source.registerCorsConfiguration("/**", config);
return new CorsFilter(source);
}
在我们的 Spring 启动应用程序中,我们已经像这样设置了 CorsConfigurationSource。
先添加allowedOrigns
然后设置applyPermitDefaultValues()
的顺序让Spring为允许的headers设置默认值,暴露headers,允许的方法,等等,所以我们不必指定这些。
public CorsConfigurationSource corsConfigurationSource() {
CorsConfiguration configuration = new CorsConfiguration();
configuration.setAllowedOrigins(Arrays.asList("http://localhost:8084"));
configuration.applyPermitDefaultValues();
UrlBasedCorsConfigurationSource configurationSource = new UrlBasedCorsConfigurationSource();
configurationSource.registerCorsConfiguration("/**", configuration);
return configurationSource;
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/api/**")
.access("@authProvider.validateApiKey(request)")
.anyRequest().authenticated()
.and().cors()
.and().csrf().disable()
.httpBasic().authenticationEntryPoint(authenticationEntryPoint);
http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
}
做一个单class就好了,这样就好了:
@Component
@Order(Ordered.HIGHEST_PRECEDENCE)
public class MyCorsConfig implements Filter {
@Override
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
final HttpServletResponse response = (HttpServletResponse) res;
response.setHeader("Access-Control-Allow-Origin", "*");
response.setHeader("Access-Control-Allow-Methods", "POST, PUT, GET, OPTIONS, DELETE");
response.setHeader("Access-Control-Allow-Headers", "Authorization, Content-Type, enctype");
response.setHeader("Access-Control-Max-Age", "3600");
if (HttpMethod.OPTIONS.name().equalsIgnoreCase(((HttpServletRequest) req).getMethod())) {
response.setStatus(HttpServletResponse.SC_OK);
} else {
chain.doFilter(req, res);
}
}
@Override
public void destroy() {
}
@Override
public void init(FilterConfig config) throws ServletException {
}
}
这对我有用,可以在 Spring 启动和 React
之间禁用 CORS@Configuration
public class CorsConfig implements WebMvcConfigurer {
/**
* Overriding the CORS configuration to exposed required header for ussd to work
*
* @param registry CorsRegistry
*/
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
.allowedOrigins("*")
.allowedMethods("*")
.allowedHeaders("*")
.allowCredentials(true)
.maxAge(4800);
}
}
我必须像下面一样修改安全配置:
@Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable()
.cors().configurationSource(new CorsConfigurationSource() {
@Override
public CorsConfiguration getCorsConfiguration(HttpServletRequest request) {
CorsConfiguration config = new CorsConfiguration();
config.setAllowedHeaders(Collections.singletonList("*"));
config.setAllowedMethods(Collections.singletonList("*"));
config.addAllowedOrigin("*");
config.setAllowCredentials(true);
return config;
}
}).and()
.antMatcher("/api/**")
.authorizeRequests()
.anyRequest().authenticated()
.and().httpBasic()
.and().sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and().exceptionHandling().accessDeniedHandler(apiAccessDeniedHandler());
}
我很惊讶只发现 Eduardo Dennis 指出了最新的解决方案,它更简单并且不需要编写您自己的过滤器 classes:它使用
org.springframework.web.bind.annotation.CrossOrigin
控制器上的注释- 并将
and().cors()
添加到您的 Spring 安全配置中。
这就是您要做的全部!
您可以像这样使用 @CrossOrigin
注释:
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller
@RequestMapping("/api")
@CrossOrigin
public class BackendController {
...
}
如果要配置 allowedHeaders
、methods
、origins
等,只需将这些值添加到注释中,如下所示:@CrossOrigin(origins = "http://localhost:50029", maxAge = 3600)
.
使用@CrossOrigin
注解,Spring安全配置变得异常简单。只需将 and().cors()
添加到您的 WebSecurityConfig.java
class:
@Configuration
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.csrf().disable()
.and().cors()
...
}
就是这样!您可以删除您的 Filter/CORSFilter classes。如果你想添加一个全局配置,你也可以声明一个 CorsConfigurationSource
。参见 this great answer or this blog post by Sébastien Deleuze)。 Spring 开发人员也明确表示:
This approach supersedes the filter-based approach previously recommended.
因此,接受的答案已过时。这也是一个完整的示例项目:https://github.com/jonashackt/microservice-api-spring-boot
要在全球启用 CORS,您需要在两个地方进行更改:
1. Spring开机:
@Configuration
public class CorsConfiguration extends WebMvcConfigurationSupport {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**").allowedOrigins("*").allowedMethods("*")
.allowCredentials(true);
}
}
您可以在 WebMvcConfigurerAdapter
中执行相同的操作,或者创建 WebMvcConfigurer
的 bean。
2。 Spring 安全性
@Override
protected void configure(HttpSecurity http) throws Exception {
http.cors().and()
.authorizeRequests()
.antMatchers(HttpMethod.OPTIONS).permitAll() //Permits your preflight request
}
在 Spring Boot 2.3 上工作。3.RELEASE
简单的方法是在 spring 引导应用程序 class(class 和 @SpringBootApplication)中创建一个 bean,如下所示:
注意!我在下面的“setAllowedOrigins()”中指定了“http://localhost:4200”,因为 运行 本地主机上的应用程序并使用 angular 默认端口。
@Bean
public CorsFilter corsFilter(){
CorsConfiguration corsConfiguration = new CorsConfiguration();
corsConfiguration.setAllowCredentials(true);
corsConfiguration.setAllowedOrigins(Arrays.asList("http://localhost:4200"));
corsConfiguration.setAllowedHeaders(Arrays.asList("Origin","Access-Control-Allow-Origin","Content-Type",
"Accept", "Authorization", "Origin, Accept", "X-Requested-With",
"Access-Control-Request-Method", "Access-Control-Request-Headers"));
corsConfiguration.setExposedHeaders(Arrays.asList("Origin", "Content-Type", "Accept","Authorization",
"Access-Control-Allow-Origin", "Access-Control-Allow-Origin", "Access-Control-Allow-Credentials"));
corsConfiguration.setAllowedMethods(Arrays.asList("GET", "POST","PUT","DELETE","OPTIONS"));
UrlBasedCorsConfigurationSource urlBasedCorsConfigurationSource = new UrlBasedCorsConfigurationSource();
urlBasedCorsConfigurationSource.registerCorsConfiguration("/**", corsConfiguration);
return new CorsFilter(urlBasedCorsConfigurationSource);
}
您可以在 sprıng boot
中的每个 restController class 上使用此注释@CrossOrigin("*")
如果您正在使用 spring 安全性,您需要在任何具有扩展 extends WebSecurityConfigurerAdapter
@Bean
CorsConfigurationSource corsConfigurationSource() {
CorsConfiguration configuration = new CorsConfiguration();
configuration.setAllowedOrigins(Arrays.asList("https://example.com"));
configuration.setAllowedMethods(Arrays.asList("GET","POST"));
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", configuration);
return source;
}