Spring Security CORS配置

好的,各位掘金的靓仔靓女们,大家好!我是你们的老朋友,代码界的段子手,Bug界的终结者——程序猿小码。今天,咱们来聊聊 Spring Security 里让人又爱又恨的 CORS 配置。

话说这 CORS,就像一对异地恋的情侣,明明相爱,却总被各种阻碍。浏览器就是那个死板的家长,动不动就来一句“跨域请求?不行,不安全!”,搞得我们开发者焦头烂额。但是,为了真爱,为了让我们的前后端小情人能够顺利“私会”,我们必须搞定它!

第一幕:CORS 登场——何方妖孽?

首先,我们得认识一下 CORS 这位“家长”。CORS,全称 Cross-Origin Resource Sharing,跨域资源共享。简单来说,就是当你的前端(比如运行在 http://localhost:8080)想去请求后端(比如运行在 http://localhost:9000)的资源时,如果这两个地址的协议、域名、端口号任何一个不同,浏览器就会认为这是跨域请求。

为啥浏览器要管这事儿呢?这是为了安全!想象一下,如果没有 CORS 限制,一个恶意网站可以随意读取你其他网站的数据,那你的银行账户、个人信息岂不是要裸奔了?想想都可怕 😱!

第二幕:浏览器的心思—— preflight 请求是个啥?

浏览器在发起跨域请求时,并不是直接就冲上去,而是先试探一下,发一个叫 preflight request 的东西。这就像情侣约会前,男生先发个短信问问:“宝贝,今天有空吗?想去看电影吗?”

这个 preflight 请求是一个 OPTIONS 请求,它会带着一些头信息,告诉服务器:“嘿,我要跨域请求啦,我用的方法是 POST,我带的头是 Content-Type,你允许吗?”

服务器收到这个 preflight 请求后,如果允许这次跨域请求,就会返回一些 CORS 相关的响应头,告诉浏览器:“嗯,允许你跨域,你可以用 POST 方法,你可以带 Content-Type 头。”

如果服务器不允许这次跨域请求,就会返回一个错误,浏览器看到错误后,就会阻止这次跨域请求。

第三幕:Spring Security 的 CORS 策略——各有千秋

Spring Security 提供了多种方式来配置 CORS,就像给情侣提供了多种约会方案,总有一款适合你。

  • 方案一:全局配置——一劳永逸的爱情

    这种方式就像父母直接认可了这段恋情,以后随便你们怎么玩,我都支持!在 Spring Boot 中,我们可以通过配置 application.propertiesapplication.yml 来实现全局 CORS 配置。

    spring:
      mvc:
        cors:
          allowed-origins: "http://localhost:8080,http://127.0.0.1:8080" # 允许的来源
          allowed-methods: "GET,POST,PUT,DELETE,OPTIONS" # 允许的请求方法
          allowed-headers: "*" # 允许的请求头
          exposed-headers: "Authorization" # 允许暴露的响应头
          allow-credentials: true # 允许携带 Cookie
          max-age: 3600 # preflight 请求的缓存时间,单位秒

    表格:全局 CORS 配置详解

    配置项 含义 举例
    allowed-origins 允许跨域请求的来源。可以是一个具体的域名,也可以是 * 表示允许所有来源(不推荐在生产环境中使用 *)。多个来源可以用逗号分隔。 "http://localhost:8080,http://127.0.0.1:8080"
    allowed-methods 允许跨域请求的方法。常用的方法有 GETPOSTPUTDELETEOPTIONS "GET,POST,PUT,DELETE,OPTIONS"
    allowed-headers 允许跨域请求携带的请求头。可以是一个具体的请求头名称,也可以是 * 表示允许所有请求头。 "*""Content-Type,Authorization"
    exposed-headers 允许浏览器访问的响应头。默认情况下,浏览器只能访问一些标准的响应头,如果服务器返回了一些自定义的响应头,并且希望浏览器能够访问这些响应头,就需要在这里配置。 "Authorization"
    allow-credentials 是否允许携带 Cookie。如果设置为 true,则表示允许跨域请求携带 Cookie。注意:如果设置为 true,则 allowed-origins 不能设置为 *,必须指定具体的域名。 truefalse
    max-age preflight 请求的缓存时间,单位秒。浏览器会缓存 preflight 请求的结果,在缓存时间内,相同的跨域请求不会再发送 preflight 请求。 3600

    优点: 配置简单,一次配置,全局生效。

    缺点: 所有接口都应用相同的 CORS 策略,不够灵活。

  • 方案二:@CrossOrigin 注解——自由恋爱的宣言

    这种方式就像情侣自己决定是否要在一起,比较自由。我们可以在 Controller 的方法或者类上使用 @CrossOrigin 注解来配置 CORS。

    import org.springframework.web.bind.annotation.CrossOrigin;
    import org.springframework.web.bind.annotation.GetMapping;
    import org.springframework.web.bind.annotation.RestController;
    
    @RestController
    @CrossOrigin(origins = "http://localhost:8080", allowedHeaders = "*")
    public class MyController {
    
        @GetMapping("/hello")
        public String hello() {
            return "Hello, CORS!";
        }
    }

    优点: 可以针对不同的接口配置不同的 CORS 策略,更加灵活。

    缺点: 需要在每个需要配置 CORS 的接口上添加注解,比较繁琐。

  • 方案三:WebMvcConfigurer——定制化的爱情合约

    这种方式就像情侣签订了一份详细的爱情合约,约定了各种细节,非常灵活。我们可以通过实现 WebMvcConfigurer 接口来定制 CORS 配置。

    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 CorsConfig implements WebMvcConfigurer {
    
        @Override
        public void addCorsMappings(CorsRegistry registry) {
            registry.addMapping("/api/**") // 匹配的路径
                    .allowedOrigins("http://localhost:8080") // 允许的来源
                    .allowedMethods("GET", "POST", "PUT", "DELETE", "OPTIONS") // 允许的请求方法
                    .allowedHeaders("*") // 允许的请求头
                    .exposedHeaders("Authorization") // 允许暴露的响应头
                    .allowCredentials(true) // 允许携带 Cookie
                    .maxAge(3600); // preflight 请求的缓存时间
        }
    }

    优点: 可以集中管理 CORS 配置,更加清晰,也更加灵活。

    缺点: 需要编写额外的配置类,稍微复杂一些。

  • 方案四:CorsFilter——拦截式的爱情守护

    这种方式就像一个忠实的保镖,拦截所有的请求,然后根据配置的 CORS 策略来处理。我们可以使用 Spring 提供的 CorsFilter 来实现 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 java.util.Arrays;
    
    @Configuration
    public class CorsFilterConfig {
    
        @Bean
        public CorsFilter corsFilter() {
            CorsConfiguration corsConfiguration = new CorsConfiguration();
            corsConfiguration.setAllowedOrigins(Arrays.asList("http://localhost:8080"));
            corsConfiguration.setAllowedMethods(Arrays.asList("GET", "POST", "PUT", "DELETE", "OPTIONS"));
            corsConfiguration.setAllowedHeaders(Arrays.asList("*"));
            corsConfiguration.setAllowCredentials(true);
            corsConfiguration.setMaxAge(3600L);
    
            UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
            source.registerCorsConfiguration("/**", corsConfiguration); // 匹配所有路径
    
            return new CorsFilter(source);
        }
    }

    优点: 可以灵活地配置 CORS 策略,并且可以与其他 Filter 配合使用。

    缺点: 需要编写额外的配置类,稍微复杂一些。

第四幕:Cookie 的秘密——信任的基石

CORS 中,Cookie 是一个非常重要的概念。如果你的跨域请求需要携带 Cookie,那么你需要做以下几件事:

  1. 在服务器端,设置 allow-credentialstrue

  2. 在客户端(比如 JavaScript),设置 withCredentialstrue

    fetch('http://localhost:9000/api/hello', {
        method: 'GET',
        credentials: 'include' // 或者 'same-origin'
    })
    .then(response => response.text())
    .then(data => console.log(data));

    注意: 如果你设置了 allow-credentialstrue,那么 allowed-origins 不能设置为 *,必须指定具体的域名。这是因为安全原因,如果允许所有来源携带 Cookie,那么就可能存在安全风险。

第五幕:调试 CORS——拨开迷雾见真相

CORS 问题有时候很隐蔽,让人摸不着头脑。这时候,我们需要一些调试技巧来拨开迷雾见真相。

  • 使用浏览器的开发者工具: 浏览器的开发者工具可以查看请求的头信息和响应头信息,以及 CORS 相关的错误信息。
  • 使用 Postman 或其他 API 客户端: Postman 可以模拟各种类型的 HTTP 请求,并且可以方便地查看请求头和响应头。
  • 查看服务器端的日志: 服务器端的日志可以记录 CORS 相关的请求和响应信息,帮助你定位问题。

第六幕:最佳实践——幸福的秘诀

最后,我们来总结一下 Spring Security CORS 配置的最佳实践,让我们的前后端小情人能够幸福地在一起。

  • 尽量使用 WebMvcConfigurerCorsFilter 来配置 CORS,这样可以集中管理 CORS 配置,更加清晰。
  • *不要在生产环境中使用 `allowed-origins: ""`,要指定具体的域名。**
  • 如果需要携带 Cookie,一定要设置 allow-credentialstrue,并且指定具体的 allowed-origins
  • 使用浏览器的开发者工具和服务器端的日志来调试 CORS 问题。

总结:

CORS 配置虽然有点复杂,但是只要我们理解了它的原理,掌握了各种配置方式,就可以轻松搞定它。记住,CORS 就像一个负责任的家长,它虽然会阻碍我们的跨域请求,但也是为了保护我们的安全。

希望今天的分享能够帮助到大家,让大家在 Spring Security 的 CORS 配置中少走弯路,早日实现前后端和谐共处的美好愿景!

好了,今天的分享就到这里,感谢大家的收听!如果大家觉得有用,记得点赞、评论、转发哦!我们下期再见! 👋

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注