文章目录
- 现象
- 解决方案
- 1. **全局配置 CORS**
- 2. **使用 `@CrossOrigin` 注解**
- 3. **配置 Spring Security**
- 4. **自定义 CORS 过滤器**
- `Spring Security 6.x 及其后续版本解决方案`
- 1. 使用 `SecurityFilterChain` 配置 CORS
- 2. 重要配置说明
- 3. 在生产环境中的最佳实践
现象
前端浏览器访问时,报错:
Access to fetch at 'http://localhost:8080/api/signature/generate' from origin 'http://127.0.0.1:5500' ![has been blocked by CORS policy](https://i-blog.csdnimg.cn/direct/a6551b463e514483b4a7647469c87caf.png)
: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. If an opaque response serves your needs, set the request's mode to 'no-cors' to fetch the resource with CORS disabled.
解决方案
在 Spring Boot 项目中解决前端浏览器访问的 CORS (Cross-Origin Resource Sharing) 问题,可以通过以下几种方式来实现:
1. 全局配置 CORS
你可以通过配置类来全局设置 CORS 规则。这种方式适用于你希望为所有的控制器和端点设置统一的 CORS 配置。
示例代码:
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;@Configuration
public class WebConfig implements WebMvcConfigurer {@Overridepublic void addCorsMappings(CorsRegistry registry) {registry.addMapping("/**").allowedOrigins("http://localhost:3000") // 允许的前端地址.allowedMethods("GET", "POST", "PUT", "DELETE", "OPTIONS") // 允许的方法.allowedHeaders("*") // 允许的头部信息.allowCredentials(true); // 是否允许携带凭证}
}
2. 使用 @CrossOrigin
注解
你可以在控制器方法或控制器类上使用 @CrossOrigin
注解来设置 CORS 策略。这种方式适用于你只希望为特定的端点设置 CORS 配置。
示例代码:
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;@RestController
@RequestMapping("/api")
public class MyController {@CrossOrigin(origins = "http://localhost:3000")@GetMapping("/data")public String getData() {return "This is CORS-enabled data.";}
}
你也可以在控制器类上使用 @CrossOrigin
注解,这样会对该类下的所有方法生效:
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;@RestController
@RequestMapping("/api")
@CrossOrigin(origins = "http://localhost:3000")
public class MyController {@GetMapping("/data")public String getData() {return "This is CORS-enabled data.";}
}
3. 配置 Spring Security
如果你的项目中使用了 Spring Security,你还需要在 Spring Security 的配置中设置 CORS。
示例代码:
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {@Overrideprotected void configure(HttpSecurity http) throws Exception {http.cors().and().authorizeRequests().anyRequest().authenticated(); // 配置你的安全规则}@Beanpublic WebMvcConfigurer corsConfigurer() {return new WebMvcConfigurer() {@Overridepublic void addCorsMappings(CorsRegistry registry) {registry.addMapping("/**").allowedOrigins("http://localhost:3000").allowedMethods("GET", "POST", "PUT", "DELETE", "OPTIONS").allowedHeaders("*").allowCredentials(true);}};}
}
4. 自定义 CORS 过滤器
你也可以定义一个自定义的 CORS 过滤器来处理跨域请求。
示例代码:
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 java.io.IOException;import org.springframework.stereotype.Component;@Component
public class SimpleCorsFilter implements Filter {@Overridepublic void init(FilterConfig filterConfig) throws ServletException {}@Overridepublic void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)throws IOException, ServletException {HttpServletRequest httpRequest = (HttpServletRequest) request;response.setContentType("text/html;charset=UTF-8");response.setHeader("Access-Control-Allow-Origin", "http://localhost:3000");response.setHeader("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS");response.setHeader("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept, Authorization");chain.doFilter(request, response);}@Overridepublic void destroy() {}
}
选择适合你项目需求的方式来配置 CORS,确保前端能够成功访问你的后端接口。
Spring Security 6.x 及其后续版本解决方案
在 Spring Security 6.x 及其后续版本中,cors()
方法已经被弃用,因此需要通过更现代的方式配置 CORS。可以直接通过 SecurityFilterChain
结合 CorsFilter
进行配置。
以下是基于 Spring Boot 3.3.2 和 Spring Security 的跨域配置示例:
1. 使用 SecurityFilterChain
配置 CORS
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
import org.springframework.web.filter.CorsFilter;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.web.SecurityFilterChain;@Configuration
public class SecurityConfig {@Beanpublic SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {// 配置跨域过滤器http.csrf().disable() // 禁用 CSRF.authorizeHttpRequests(authz -> authz.anyRequest().authenticated() // 根据需要配置权限).addFilter(corsFilter()); // 添加自定义的 CORS 过滤器return http.build();}@Beanpublic CorsFilter corsFilter() {UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();CorsConfiguration config = new CorsConfiguration();config.setAllowCredentials(true); // 允许客户端携带凭证(如 Cookies)config.addAllowedOriginPattern("*"); // 允许所有域名,生产环境可以改为特定域名config.addAllowedHeader("*"); // 允许所有请求头config.addAllowedMethod("*"); // 允许所有 HTTP 方法(GET, POST, PUT, DELETE 等)source.registerCorsConfiguration("/**", config);return new CorsFilter(source);}
}
2. 重要配置说明
config.addAllowedOriginPattern("*")
:这个方法用于允许所有来源的请求,addAllowedOriginPattern
替代了以前的addAllowedOrigin
,并更灵活地支持正则表达式。addAllowedMethod("*")
:允许所有 HTTP 请求方法。addAllowedHeader("*")
:允许所有请求头。
3. 在生产环境中的最佳实践
为了确保安全,在生产环境中,建议将 addAllowedOriginPattern
限制为特定的域名,而不是使用 "*"
来允许所有来源。这样可以避免潜在的安全风险。
这个配置通过 CorsFilter
实现了跨域支持,而不是依赖已被弃用的 .cors()
方法。这种方式在 Spring 3.3.2 和 Spring Security 中是推荐的做法。