Spring Security专栏(使用 Spring Security 实现 CORS)

699 阅读5分钟

这是我参与11月更文挑战的第5天,活动详情查看:2021最后一次更文挑战

写在前面

开篇引入一下今天的天气吧,坐标北京,今天周六(2021.11.6)北京入冬的第一场雪,还贼大。你们的城市下雪了没,哈哈 注意保暖。

拉回正题。温故而知新,上文我们讲CSRF ,是一种保护我们应用的一种机制,并且如何定制化CSRF,以及各组件之间的关系。欢迎大家去查看我写的上一篇文章。

这里多唠叨一句,欢迎大家查看我的专栏,目前正在进行的Security专栏和队列并发专栏,设计模式专题(已完结)

今天我们一起学习下如何实现跨域(CORS)。

什么是 CORS?

介绍完 CSRF,我们继续来看 Web 应用程序开发过程中另一个常见的需求——CORS,即跨域资源共享(Cross-Origin Resource Sharing)。那么问题来了

Q: 什么叫跨域

A: 当下的 Web 应用程序开发基本都采用了前后端分离的开发模式,数据的获取并非同源,所以跨域问题在我们日常开发中特别常见。例如,当我们从“test.com”这个域名发起请求时,浏览器为了一定的安全因素考虑,并不会允许请求去访问“api.test.com”这个域名,因为请求已经跨越了两个域名。

请注意,跨域是浏览器的一种同源安全策略,是浏览器单方面限制的,所以仅在客户端运行在浏览器中才需要考虑这个问题。从原理上讲,实际就是浏览器在 HTTP 请求的消息头部分新增一些字段,如下所示:

//浏览器自己设置的请求域名
Origin     
//浏览器告诉服务器请求需要用到哪些 HTTP 方法
Access-Control-Request-Method
//浏览器告诉服务器请求需要用到哪些 HTTP 消息头
Access-Control-Request-Headers

当浏览器进行跨域请求时会和服务器端进行一次的握手协议,从响应结果中可以获取如下信息:

//指定哪些客户端的域名允许访问这个资源
Access-Control-Allow-Origin 
//服务器支持的 HTTP 方法
Access-Control-Allow-Methods 
//需要在正式请求中加入的 HTTP 消息头
Access-Control-Allow-Headers 

因此,实现 CORS 的关键是服务器。只要服务器合理设置这些响应结果中的消息头,就相当于实现了对 CORS 的支持,从而支持跨源通信。

下面我们一起看下有什么办法解决跨域

使用 CorsFilter

和我们上文讲到的 CsrfFilter 注解一样,在 Spring 中也存在一个 CorsFilter 过滤器,不过这个过滤器并不是 Spring Security 提供的,而是来自Spring Web MVC。在 CorsFilter 这个过滤器中

首先应该判断来自客户端的请求是不是一个跨域请求,然后根据 CORS 配置来判断该请求是否合法,如下所示:

@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response,
             FilterChain filterChain) throws ServletException, IOException {
 
        if (CorsUtils.isCorsRequest(request)) {
             CorsConfiguration corsConfiguration = this.configSource.getCorsConfiguration(request);
             if (corsConfiguration != null) {
                 boolean isValid = this.processor.processRequest(corsConfiguration, request, response);
                 if (!isValid || CorsUtils.isPreFlightRequest(request)) {
                     return;
                 }
             }
        }
 
        filterChain.doFilter(request, response);
}

上述操作的内容是创建合适的配置类 CorsConfiguration。根据 CorsFilter,Spring Security 也在 HttpSecurity 工具类通过提供了 cors() 方法来创建 CorsConfiguration

使用方式如下所示:

@Override
protected void configure(HttpSecurity http) throws Exception {
        http.cors(c -> {
            CorsConfigurationSource source = request -> {
                CorsConfiguration config = new CorsConfiguration();
                config.setAllowedOrigins(Arrays.asList("*"));
                config.setAllowedMethods(Arrays.asList("*"));
                return config;
            };
            c.configurationSource(source);
        });
}

我们可以通过 setAllowedOrigins() 和 setAllowedMethods() 方法实现对 HTTP 响应消息头的设置。这里将它们都设置成“*”,意味着所有请求都可以进行跨域访问。你也可以根据需要设置特定的域名和 HTTP 方法。

使用 @CrossOrigin 注解

通过 CorsFilter,我们实现了全局级别的跨域设置。但有时候,我们可能只需要针对某些请求实现这一功能,通过 Spring Security 也是可以做到这一点的,我们可以在特定的 HTTP 端点上使用如下所示的 @CrossOrigin 注解:

@Controller
public class TestController {
        
    @PostMapping("/hello")
	@CrossOrigin("http://api.test.com:8080")
    public String hello() {
        return "hello";
    }
}

默认情况下,@CrossOrigin 注解允许使用所有的域和消息头,同时会将 Controller 中的方法映射到所有的 HTTP 方法。

好的 今天关于实现跨域的讲解就到这里。

总结

针对上一讲和这一讲中,我们一起做下总结。我们讨论了日常开发过程中常见的两个概念,即 CSRF 和 CORS。这两个概念有时候容易混淆,但应对的是完全不同的两种场景。

所以分开两篇来讲 能让大家分的更清

CSRF 是一种攻击行为,所以我们需要对系统进行保护,而 CORS 更多的是一种前后端开发模式上的约定。在 Spring Security 中,针对这两个场景都提供了对应的过滤器,我们只需要通过简单的配置方法就能在系统中自动集成想要的功能。

好的 我们下期再见,加油!!!

弦外之音

感谢你的阅读,如果你感觉学到了东西,您可以点赞,关注。也欢迎有问题我们下面评论交流

加油! 我们下期再见!

给大家分享几个我前面写的几篇骚操作

copy对象,这个操作有点骚!

干货!SpringBoot利用监听事件,实现异步操作