Spring Boot公开API防直接访问:仅允许指定前端域名通过CORS调用
Spring Boot 端具体实现方案
1. 严格配置CORS规则
Spring Security的CORS配置是基础,必须精准指定允许的前端域名,拒绝通配符。这样浏览器会自动拦截跨域请求,只有指定域名的前端能发起合法请求。
@Configuration @EnableWebSecurity public class SecurityConfig { @Bean public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { http .cors(cors -> cors.configurationSource(corsConfigurationSource())) .authorizeHttpRequests(auth -> auth .requestMatchers("/api/public/**").permitAll() .anyRequest().authenticated() ); return http.build(); } private CorsConfigurationSource corsConfigurationSource() { CorsConfiguration config = new CorsConfiguration(); // 仅允许指定前端域名,注意匹配实际域名格式 config.setAllowedOrigins(List.of("https://frontend.com/myapp")); // 按需开放请求方法,避免过度授权 config.setAllowedMethods(List.of("GET", "POST", "PUT", "DELETE")); config.setAllowedHeaders(List.of("Authorization", "Content-Type")); // 如需携带Cookie则设为true,否则保持false config.setAllowCredentials(true); // 缓存预检请求结果,减少OPTIONS请求开销 config.setMaxAge(3600L); UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(); source.registerCorsConfiguration("/api/public/**", config); return source; } }
2. 新增Origin请求头校验过滤器
CORS是浏览器层面的限制,非浏览器工具(如Postman)可以伪造Origin头,所以需要在后端加一层校验:直接访问(地址栏输入、无Origin头)或Origin不匹配的请求直接拒绝。
@Component public class PublicApiGuardFilter extends OncePerRequestFilter { private static final String ALLOWED_ORIGIN = "https://frontend.com/myapp"; private static final String PUBLIC_API_PREFIX = "/api/public/"; @Override protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException { String uri = request.getRequestURI(); if (uri.startsWith(PUBLIC_API_PREFIX)) { String origin = request.getHeader("Origin"); // 无Origin或Origin不匹配直接返回403 if (origin == null || !ALLOWED_ORIGIN.equals(origin)) { response.setStatus(HttpServletResponse.SC_FORBIDDEN); response.getWriter().write("Access denied: Invalid request origin"); return; } } filterChain.doFilter(request, response); } }
然后在SecurityConfig里注册这个过滤器,要放在CORS过滤器之前:
@Bean public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { http .addFilterBefore(new PublicApiGuardFilter(), CorsFilter.class) .cors(cors -> cors.configurationSource(corsConfigurationSource())) .authorizeHttpRequests(auth -> auth .requestMatchers("/api/public/**").permitAll() .anyRequest().authenticated() ); return http.build(); }
3. 可选:添加轻量API Key认证
如果要彻底防止非授权工具访问,可以给前端分配专属API Key,要求请求public端点时在X-API-Key头里携带,后端校验Key的合法性。这种方式比Origin校验更可靠,因为Origin可以伪造,但API Key只有授权前端持有(务必通过HTTPS传输)。
示例校验逻辑(可集成到上述过滤器中):
String apiKey = request.getHeader("X-API-Key"); if (!"YOUR_SECRET_FRONTEND_KEY".equals(apiKey)) { response.setStatus(HttpServletResponse.SC_FORBIDDEN); response.getWriter().write("Access denied: Invalid API key"); return; }
行业及企业内部常见做法
网关层统一管控
大部分中大型企业会用API网关(Spring Cloud Gateway、Kong、Nginx)集中处理CORS、来源校验、流量控制。把这些安全逻辑从业务服务剥离,便于统一维护。比如Nginx配置:location /api/public/ { # 校验Origin if ($http_origin != "https://frontend.com/myapp") { return 403; } # 配置CORS响应头 add_header Access-Control-Allow-Origin $http_origin; add_header Access-Control-Allow-Methods "GET,POST,PUT,DELETE"; add_header Access-Control-Allow-Headers "Authorization,Content-Type,X-API-Key"; add_header Access-Control-Max-Age 3600; # 转发到后端服务 proxy_pass http://backend-service-cluster; }CORS + Origin校验组合
小型团队或项目通常直接在Spring Boot里配置CORS加Origin过滤器,快速实现需求,成本低。IP白名单限制
如果前端部署在固定IP的服务器(比如企业内部系统),可以在防火墙或后端配置IP白名单,仅允许前端服务器IP访问public端点。但这种方式不适合前端用CDN或动态IP的场景。CSRF Token增强(针对单页应用)
对于SPA前端,会配合CSRF Token机制,要求请求public端点时携带CSRF Token,直接访问(无Token)会被拒绝。但需要前端配合从Cookie获取Token并在请求头携带。
关键注意点
- 浏览器地址栏直接访问public端点时不会发送Origin头,过滤器会直接返回403,满足你的需求。
- 非浏览器工具可以伪造Origin,所以如果要完全杜绝,必须配合API Key或其他认证方式,CORS本身是浏览器安全机制,对非浏览器客户端无效。
- 确保所有public端点都被纳入校验范围,不要遗漏路径。
内容的提问来源于stack exchange,提问作者Abhay Sonu

