关于Spring Security的CORS

目录

一、CORS是什么

二、同源安全策略

[三、Spring Security中CORS的开启](#三、Spring Security中CORS的开启)

四、其它处理方法


一、CORS是什么

CORS(Cross-Origin Resource Sharing,跨源/域资源共享 )是一个W3C标准,一种允许当前域(domain)的资源(比如html/js/web service)被其他域(domain)的脚本(比如AJAX)请求访问的机制,通常由于同源安全策略,浏览器会禁止这种跨域请求。

CORS需要浏览器和服务器同时支持。目前,所有浏览器都支持该功能,IE 浏览器不能低于 IE10。

整个CORS通信过程,都是浏览器自动完成,不需要用户参与。对于开发者来说,CORS通信与同源的AJAX通信没有差别,代码完全一样。浏览器一旦发现AJAX请求跨源,就会自动添加一些附件的头信息,有时还会多处一次附件的请求,但用户不会有感觉。

因此,实现CORS通信的关键是服务器。只要服务器实现了CORS功能(响应报文包括了正确的CORS响应头),就可以被跨源访问(可以指定个别域或全部域)。

二、同源安全策略

说到跨域请求,就不得不说一下"同源安全策略"了,如果没有这个策略的存在,也就没有这么多事了,但是,这样可能会造成你在网站进行一些操作时存在风险。

同源策略是一个重要的安全策略,它用于限制一个源/域的文档或它加载的脚本是否能与另一个源/域的资源进行交互。它能帮助阻隔恶意文档,减少可能被攻击的媒介。

出于安全性,浏览器会限制脚本内发起的跨域HTTP请求,例如常见的 XHR、Fetch API 都遵循同源策略。

如果两个 URL 的协议(Protocol)、主机(Host)、端口(Port,如果有指定的话)都相同的话,那么这两个 URL 是同源的,否则是不同源的。

当浏览器中打开的某个网页,有脚本执行了跨域请求,那么,浏览器的"同源安全策略"就会介入,大致流程如下:

浏览器直接发出CORS请求,也就是在头信息之中,增加一个Origin字段。这个字段代表本次请求来自哪个源(协议 + 主机 + 端口),服务器会根据这个值,决定是否同意这次请求。前面的流程是对于HTTP简单请求,如果是HTTP非简单请求,则会在正式请求前,增加一次预检请求。

如果Origin指定的源,不在许可范围内(服务器端CORS功能指定),服务器会返回一个正确的HTTP回应。浏览器发现,这个回应的头信息没有包含Access-Control-Allow-Origin字段,就知道出错了,从而抛出一个错误,被XMLHttpRequestonerror回调函数捕获。注意,这种错误无法通过状态识别,因为HTTP回应的状态码有可能是 200

抛出的错误为"has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource.",如下:

三、Spring Security中CORS的开启

在Spring框架中,我们可以在引入Spring Security依赖后,对Security的HttpSecurity进行设置,来开启CORS(跨域/源资源共享),同时能指定只被部分域/源、部分方法、部分头部信息访问资源。

Spring框架提供了CorsFilter,是为了在基于filter的安全框架(如Spring Security)上面支持CORS,或者在使用其他不支持CORS的库上支持CORS。

java 复制代码
//(Security6.2.4写法)先创建一个普通JAVA类,如SecurityConfig.java,实现如下3个Bean。
    @Bean
    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
        http.authorizeHttpRequests(
                (authz) -> authz
                        .anyRequest().authenticated())
            .httpBasic(withDefaults())
            .formLogin(withDefaults())
            .csrf((csrf)->csrf.disable())
            .cors(withDefaults()); //开启CORS(跨域/源资源共享)
        return http.build();
    }

    @Autowired //自动装配参数configurationSource(下方的Bean)
    @Bean
    public CorsFilter corsFilter(UrlBasedCorsConfigurationSource configurationSource){
        return new CorsFilter(configurationSource);
    }

    // 也可以将方法内的实现整合到上面的corsFilter方法体内
    @Bean
    public UrlBasedCorsConfigurationSource configurationSource(){
        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        CorsConfiguration corsConfiguration = new CorsConfiguration();
        corsConfiguration.setAllowCredentials(true);
        corsConfiguration.addAllowedHeader("*");
        corsConfiguration.addAllowedMethod("*");
        corsConfiguration.addAllowedOriginPattern("http://localhost*"); //新版本写法
        //corsConfiguration.addAllowedOrigin("*"); //老版本写法
        source.registerCorsConfiguration("/**",corsConfiguration);
        return source;
    }

四、其它处理方法

1、Spring注解

原理:自Spring Framework 4.2开始,CORS请求(包括OPTIONS method)会被自动分发到各种注册过的HandlerMappings。它们会处理CORS的preflight请求,会拦截CORS简单和实际请求,以便基于你指定的CORS配置,添加相关的CORS响应头(如 Access-Control-Allow-Origin)。

实现:在@RequestMapping注解过的controller method上面添加@CrossOrigin注解,表示已开启CORS。

java 复制代码
@CrossOrigin(origins = "http://domain2.com", maxAge = 3600) //括号内为指定的CORS配置
@RestController
@RequestMapping("/account")
public class AccountController {

    @CrossOrigin("http://domain2.com") //同时使用controller级别和method级别的CORS配置,Spring会将二者的attributes结合起来,创建出融合的CORS配置。
    @RequestMapping("/{id}")
    public Account retrieve(@PathVariable Long id) {
        // ...
    }
}

除了基于注解@CrossOrigin的配置(细粒度),还可以定义全局的CORS配置。类似于使用filters,但可以定义在Spring MVC中,并与细粒度的@CrossOrigin配置相配合。

2、JSONP(JSON with Padding)

原理:利用<script>标签不受浏览器同源策略限制的特性,通过动态插入<script>标签的方式实现跨域数据访问。

实现:客户端创建一个<script>标签,将请求后端的接口URL拼接一个回调函数名称作为参数传给后端,并设置给<script>标签的src属性。后端接收到请求后,将数据和回调函数名称拼接成函数调用的形式返回。客户端在接收到响应后,会执行这个回调函数,从而获取到后端返回的数据。

3、使用代理服务器

原理:通过搭建一个代理服务器来转发客户端的请求,代理服务器与目标服务器进行通信,然后将返回的数据再转发给客户端。由于客户端和代理服务器、代理服务器和目标服务器之间的通信都在服务器端进行,因此不受浏览器同源策略的限制。

实现:可以使用Nginx、Node.js等搭建代理服务器。例如,Nginx可以通过配置反向代理来解决跨域问题;Node.js可以搭建一个中间层服务器,接收客户端的请求,然后将请求转发给目标服务器,并将返回的数据再转发给客户端。

4、前端正向代理

原理:在客户端设置一个代理服务器,并指定目标服务器。代理服务器向目标服务器转交请求,并将获得的内容发送给客户端。这种方式在客户端进行了请求转发,但同样实现了跨域请求。

实现:可以通过在客户端代码中配置代理服务器地址和端口,以及目标服务器的地址和端口来实现。在发送请求时,将请求地址替换为代理服务器的地址,并在代理服务器中进行请求转发。

5、配置浏览器插件或工具

有些浏览器插件或工具(如Postman、curl等)可以绕过浏览器的同源策略限制,直接发送跨域请求。但这种方法主要用于开发和测试阶段,不建议在生产环境中使用。

相关文章:关于Spring Security的CSRF

相关推荐
ejinxian29 分钟前
Spring AI Alibaba 快速开发生成式 Java AI 应用
java·人工智能·spring
杉之34 分钟前
SpringBlade 数据库字段的自动填充
java·笔记·学习·spring·tomcat
圈圈编码1 小时前
Spring Task 定时任务
java·前端·spring
爱的叹息1 小时前
Java 连接 Redis 的驱动(Jedis、Lettuce、Redisson、Spring Data Redis)分类及对比
java·redis·spring
松韬2 小时前
Spring + Redisson:从 0 到 1 搭建高可用分布式缓存系统
java·redis·分布式·spring·缓存
天上掉下来个程小白2 小时前
Redis-14.在Java中操作Redis-Spring Data Redis使用方式-操作列表类型的数据
java·redis·spring·springboot·苍穹外卖
汤姆大聪明3 小时前
Redisson 操作 Redis Stream 消息队列详解及实战案例
redis·spring·缓存·maven
正经摸鱼5 小时前
classpath与classpath*实现逻辑
后端·spring
良枫5 小时前
Spring Security认证授权深度解析
spring boot·spring
BeerBear6 小时前
记一次Kill <Pid> Java进程无法退出的问题处理
java·后端·spring