Spring Security - 跨域资源共享(CORS)

Spring Security - 跨域资源共享(CORS)详解

1. 什么是 CORS?

CORS(Cross-Origin Resource Sharing,跨域资源共享) 是一种 W3C 标准,用于解决浏览器中的跨域请求问题。通常情况下,浏览器安全策略限制了 Web 应用只能从同一个域名(origin)请求资源,而不能访问不同域名、端口或协议的资源。这是出于安全考虑,防止恶意网站未经授权读取用户数据。

然而,在实际的 Web 开发中,前端与后端分离架构越来越普遍,前端应用和后端 API 通常部署在不同的域名或端口上,这种场景下,跨域请求变得不可避免。CORS 允许服务器通过设置 HTTP 头来告诉浏览器,哪些跨域请求是被允许的。

2. CORS 基本原理

CORS 的工作原理依赖于 HTTP 请求中的一些特殊头字段。典型的跨域请求包括两种类型:

  1. 简单请求:只涉及 GET、HEAD、POST 方法,且不包含自定义的请求头。
  2. 预检请求(Preflight Request):如果请求方法不是简单方法(例如 PUT、DELETE),或包含自定义头字段,浏览器会先发送一个 OPTIONS 请求进行预检,询问服务器是否允许该跨域请求。

浏览器在处理跨域请求时,主要会涉及以下几个 HTTP 头字段:

  • Access-Control-Allow-Origin:指定允许哪些源发起请求。
  • Access-Control-Allow-Methods:指定允许的 HTTP 方法,例如 GET、POST、PUT 等。
  • Access-Control-Allow-Headers:允许客户端发送的请求头。
  • Access-Control-Allow-Credentials:是否允许发送认证信息(如 Cookies)。
  • Access-Control-Max-Age:指定预检请求的结果在客户端缓存的时间。
3. Spring Security 与 CORS

Spring Security 的默认行为是拒绝所有跨域请求,因为它专注于安全保护。为了允许跨域请求,需要在 Spring Security 中配置 CORS 策略。

通常,CORS 配置分为两个部分:

  1. Spring MVC 层:通过 @CrossOrigin 注解或全局配置来设置允许的跨域规则。
  2. Spring Security 层:通过在 HttpSecurity 中启用 CORS 支持。
4. Spring MVC 层的 CORS 配置

在 Spring 框架中,@CrossOrigin 注解可以用于控制特定控制器或方法的跨域请求。下面是一个简单的示例:

@RestController
@RequestMapping("/api")
public class MyController {

    @CrossOrigin(origins = "http://example.com")  // 允许来自 http://example.com 的跨域请求
    @GetMapping("/data")
    public ResponseEntity<String> getData() {
        return ResponseEntity.ok("Data from server");
    }
}

在这个例子中,@CrossOrigin 注解指定了只允许 http://example.com 这个域的请求访问 /api/data 接口。如果需要允许多个域名,可以指定多个 URL:

@CrossOrigin(origins = {"http://example.com", "http://another.com"})

除了在控制器或方法上配置 CORS,还可以通过全局配置来统一管理 CORS 规则。这通常在 WebMvcConfigurer 中实现:

@Configuration
public class WebConfig implements WebMvcConfigurer {

    @Override
    public void addCorsMappings(CorsRegistry registry) {
        registry.addMapping("/**")
            .allowedOrigins("http://example.com")  // 允许的跨域源
            .allowedMethods("GET", "POST", "PUT", "DELETE")  // 允许的方法
            .allowedHeaders("*")  // 允许的请求头
            .allowCredentials(true)  // 是否允许发送 Cookie
            .maxAge(3600);  // 预检请求的缓存时间
    }
}

此配置全局应用于所有的 URL 模式,控制哪些跨域请求是被允许的。

5. 在 Spring Security 中启用 CORS 支持

当我们在 Spring MVC 中配置了 CORS,仍然需要在 Spring Security 中启用 CORS 支持,否则 Spring Security 的默认安全机制会拒绝这些跨域请求。

要在 Spring Security 中启用 CORS,只需要在 HttpSecurity 配置中调用 cors() 方法:

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
            .cors()  // 启用 CORS 支持
            .and()
            .csrf().disable()  // 如果使用的是无状态的 REST API,通常会禁用 CSRF
            .authorizeRequests()
            .antMatchers("/public/**").permitAll()
            .anyRequest().authenticated();
    }

    @Bean
    public CorsConfigurationSource corsConfigurationSource() {
        CorsConfiguration configuration = new CorsConfiguration();
        configuration.setAllowedOrigins(Arrays.asList("http://example.com"));
        configuration.setAllowedMethods(Arrays.asList("GET", "POST", "PUT", "DELETE"));
        configuration.setAllowedHeaders(Arrays.asList("Authorization", "Cache-Control", "Content-Type"));
        configuration.setAllowCredentials(true);
        configuration.setMaxAge(3600L);  // 预检请求结果缓存 1 小时

        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        source.registerCorsConfiguration("/**", configuration);
        return source;
    }
}

在这个配置中,我们通过 cors() 方法启用了 Spring Security 对 CORS 请求的支持,并且通过 CorsConfigurationSource 自定义了允许的跨域规则。

5.1 Spring Security 中的 CORS 与 CSRF

在 RESTful API 开发中,通常会禁用 CSRF 保护,因为它主要用于防止跨站请求伪造攻击,这类攻击对无状态的 REST API 并没有太大影响。因此,在大多数情况下,开发者会同时禁用 CSRF 和启用 CORS 支持。

http
    .cors()
    .and()
    .csrf().disable();  // 禁用 CSRF 防护

禁用 CSRF 不影响 CORS 的处理,反而简化了 REST API 的请求逻辑,尤其是对于跨域请求来说。

6. 处理 CORS 的常见问题
6.1 预检请求未通过

当浏览器发送预检请求(OPTIONS 请求)时,服务器需要正确响应带有 Access-Control-Allow-OriginAccess-Control-Allow-Methods 等头信息。如果没有正确配置,浏览器会阻止后续的跨域请求。

可以通过 Spring Security 的 CorsConfigurationSource 正确配置预检请求的响应:

configuration.setAllowedMethods(Arrays.asList("GET", "POST", "PUT", "DELETE"));

确保服务器返回正确的 Access-Control-Allow-Methods

6.2 自定义头信息问题

当前端应用发送包含自定义头(例如 Authorization)的跨域请求时,需要明确允许这些头信息:

configuration.setAllowedHeaders(Arrays.asList("Authorization", "Cache-Control", "Content-Type"));

如果服务器不允许这些自定义头信息,浏览器将不会继续请求。

6.3 Cookie 的跨域问题

如果需要在跨域请求中发送 Cookie,必须在 CORS 配置中允许 credentials,同时前端的请求也需要设置 withCredentialstrue

  • 后端:
configuration.setAllowCredentials(true);
  • 前端(例如使用 Axios):
axios.defaults.withCredentials = true;

此外,Access-Control-Allow-Origin 不能设置为 *,而必须明确指定允许的域名。

7. 总结

Spring Security 对 CORS 的处理提供了非常灵活且强大的支持,允许开发者通过多种方式来配置跨域访问控制。典型的 CORS 处理包括在 Spring MVC 中进行全局或局部配置,并在 Spring Security 中启用对跨域请求的支持。

在实践中,确保前后端跨域请求的正常工作,通常需要结合正确的 CORS 规则设置、Cookie 管理以及请求头的处理。通过合理的配置,可以让跨域请求既安全又高效。

Spring Security中配置跨域有多种方法。一种常见的方法是使用@CrossOrigin注解或重写addCorsMappings方法来配置跨域,但是当项目中引入了Spring Security依赖后,这种配置方式可能会失效。 为了解决这个问题,可以使用Spring Security提供的更专业的跨域方案。首先,需要创建一个继承自WebSecurityConfigurerAdapter的配置类,并重写configure方法。在configure方法中,可以通过调用HttpSecurity对象的cors方法来启用跨域配置。 在cors方法中,可以通过CorsConfigurationSource对象的configurationSource方法来配置具体的跨域设置。可以使用CorsConfiguration对象来设置允许的请求头、请求方法和请求来源。此外,还可以设置预检请求的缓存时间。最后,需要将CorsConfiguration对象注册到UrlBasedCorsConfigurationSource对象中。 下面是一个示例的配置类的代码: ```java @Configuration public class WebSecurityConfig extends WebSecurityConfigurerAdapter { @Override protected void configure(HttpSecurity http) throws Exception { http.authorizeRequests() .mvcMatchers("/hello1").permitAll() .anyRequest().authenticated() .and() .formLogin() .and() .cors() // 跨域配置 .configurationSource(configurationSource()); } CorsConfigurationSource configurationSource() { CorsConfiguration corsConfiguration = new CorsConfiguration(); corsConfiguration.setAllowedHeaders(Collections.singletonList("*")); corsConfiguration.setAllowedMethods(Collections.singletonList("*")); corsConfiguration.setAllowedOrigins(Collections.singletonList("*")); corsConfiguration.setMaxAge(3600L); UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(); source.registerCorsConfiguration("/**", corsConfiguration); return source; } } ``` 通过以上配置,Spring Security会自动应用跨域配置,并且保持其他安全配置不受影响。这种方式可以确保跨域配置在Spring Security过滤器之前生效,避免了跨域配置失效的问题。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* *3* [Spring Security(七) ——跨域配置](https://blog.csdn.net/tongkongyu/article/details/125982927)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 100%"] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值