文章目录
- 现象
- 解决方案
- 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 {
@Override
public 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 {
@Override
protected void configure(HttpSecurity http) throws Exception {
http.cors().and()
.authorizeRequests()
.anyRequest().authenticated(); // 配置你的安全规则
}
@Bean
public WebMvcConfigurer corsConfigurer() {
return new WebMvcConfigurer() {
@Override
public 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 {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
@Override
public 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);
}
@Override
public 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 {
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
// 配置跨域过滤器
http
.csrf().disable() // 禁用 CSRF
.authorizeHttpRequests(authz -> authz
.anyRequest().authenticated() // 根据需要配置权限
)
.addFilter(corsFilter()); // 添加自定义的 CORS 过滤器
return http.build();
}
@Bean
public 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 中是推荐的做法。