同源策略是浏览器的一个安全限制,要求域名、协议、端口相同,如果不同则没办法进行数据交互。
而跨域配置,则是为了解除这方面的限制。
前后端分离的情况下,因为需要分开部署,后台开发基本都需要进行跨域配置了。
(当然,这也可以在 nginx 上处理,这里就不展开讨论了)

spring 提供的跨域拦截器是 CorsFilter,与 CorsFilter 强关联的类是 UrlBasedCorsConfigurationSource。

跨域配置实体类

参数介绍可以看代码注释

 * 跨域配置一览:
* <p>
* Access-Control-Allow-Origin: 允许访问的域名
* Access-Control-Allow-Methods: 允许访问的请求方式
* Access-Control-Allow-Headers: 允许使用的Header
* Access-Control-Allow-Credentials: 是否允许用户发送、处理Cookie
* Access-Control-Max-Age: 预检有效期,单位为秒。有效期内,不需要重复发送预检请求
* Access-Control-Expose-Headers: Header白名单,不设置的话,客户端读不到header的内容
*
* @author Mr.css
* @date 2022-03-09 16:55
*/
public class CrossDomain implements Serializable {
private static final long serialVersionUID = -3682297338044962128L;
/**
* 路径,Controller提供的接口
*/
@Length(max = 64)
@Schema(description = "路径")
private String antPath;
/**
* 允许访问的IP
*/
@Length(max = 64)
@Schema(description = "允许访问的IP")
private String allowedOrigin;
/**
* 开放请求头
*/
@Length(max = 64)
@Schema(description = "允许的请求头")
private String allowedHeader;
/**
* 开放请求方式
*/
@Length(max = 32)
@Schema(description = "允许的请求方式")
private String allowedMethod;
/**
* 白名单Header
*/
@Length(max = 64)
@Schema(description = "白名单Header")
private String exposedHeader;
/**
* 预检请求有效期
*/
@Schema(description = "预检请求有效期")
private Integer maxAge;
/**
* 允许携带凭证
*/
@Schema(description = "允许携带凭证")
private Boolean allowCredentials; // 省略getter/setter

Yml配置

YML配置方式,与实体类字段对应

boot-cross-domain:
config:
allowed-origin: 'http://localhost:8080'
ant-path: '/**'
allowed-header: '*'
allowed-method: '*'
allow-credentials: true

默认配置方式(单个跨域)

如果客户端不多,默认的配置就已经很好用了。

import cn.seaboot.common.core.CommonUtils;
import cn.seaboot.common.lang.Warning;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.Ordered;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
import org.springframework.web.filter.CorsFilter; /**
* 跨域配置
*
* @author Mr.css
* @date 2020-07-08 09:04
**/
@Configuration
@ConfigurationProperties(prefix = "boot-cross-domain")
public class CrossDomainStarter {
private Logger logger = LoggerFactory.getLogger(CrossDomainStarter.class); private CrossDomain config; public CrossDomain getConfig() {
return config;
} public void setConfig(CrossDomain config) {
this.config = config;
} @Bean
@SuppressWarnings(Warning.UNCHECKED)
public FilterRegistrationBean corsFilter() {
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
logger.info("【Configuration】Cross domain setting: start...");
CorsConfiguration corsConfiguration = new CorsConfiguration();
String origin = config.getAllowedOrigin();
if (origin.endsWith("/") || origin.endsWith("\\")) {
origin = origin.substring(0, origin.length() - 2);
}
corsConfiguration.addAllowedOrigin(origin); //AllowedHeader
String allowHeader = config.getAllowedHeader();
if (CommonUtils.isNotEmpty(allowHeader)) {
for (String header : allowHeader.split(",")) {
corsConfiguration.addAllowedHeader(header);
}
} //AllowedMethod
String allowedMethod = config.getAllowedMethod();
if (CommonUtils.isNotEmpty(allowedMethod)) {
for (String method : allowedMethod.split(",")) {
corsConfiguration.addAllowedMethod(method);
}
}//AllowedHeader
String exposedHeader = config.getExposedHeader();
if (CommonUtils.isNotEmpty(exposedHeader)) {
for (String header : exposedHeader.split(",")) {
corsConfiguration.addExposedHeader(header);
}
} //MaxAge
if (config.getMaxAge() != null) {
corsConfiguration.setMaxAge(config.getMaxAge().longValue());
} //AllowCredentials
if (config.getAllowCredentials() != null) {
corsConfiguration.setAllowCredentials(config.getAllowCredentials());
}
logger.info("Cross domain using config: {}", config);
source.registerCorsConfiguration(config.getAntPath(), corsConfiguration);
logger.info("【Configuration】Cross domain setting: finish");
FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean(new CorsFilter(source));
filterRegistrationBean.setOrder(Ordered.HIGHEST_PRECEDENCE);
return filterRegistrationBean;
}
}

配置多个跨域

 * Access-Control-Allow-Origin:         允许访问的域名
* Access-Control-Allow-Methods: 允许访问的请求方式
* Access-Control-Allow-Headers: 允许使用的Header
* Access-Control-Allow-Credentials: 是否允许用户发送、处理Cookie

这些参数本身就可以配置多个,用逗号分隔即可。

增加更多的跨域配置

逗号拼接的方式,决定了功能上限,如果有很多个客户端,配置起来就会很乱,比如说,我有10个客户端要配置怎么办?
这种场景下,通常会选择直接使用通配符 *,放开跨域拦截,通过业务控制,或者通过鉴权系统控制。

虽说如此,强行实现一波,应当如何?

直接看源码,上面我们用到了 UrlBasedCorsConfigurationSource,
UrlBasedCorsConfigurationSource 的父类是 CorsConfigurationSource,
这个类,相当于Dao,参数是 request,根据 request 的内容查找对应的跨域配置。

我们可以自己实现一个 CorsConfigurationSource。
代码贴出来显得文章篇幅太大,而且代码功能单一,就是配置查询,这次就简单地说明一下,下面提供了伪代码作为参考。

    @Override
@Nullable
public CorsConfiguration getCorsConfiguration(@NotNull HttpServletRequest request) {
String lookupPath = this.urlPathHelper.getLookupPathForRequest(request);
// 获取客户端域名
String origin = request.getHeader(HttpHeaders.ORIGIN);
// TODO: 根据客户端的域名,查找CorsConfiguration配置
return null;
}

SpringBoot(十五)单个以及多个跨域的配置方法的更多相关文章

  1. springboot(十八):CORS方式实现跨域

    资料 https://www.cnblogs.com/toutou/p/9843588.html

  2. SpringBoot 优雅配置跨域多种方式及Spring Security跨域访问配置的坑

    前言 最近在做项目的时候,基于前后端分离的权限管理系统,后台使用 Spring Security 作为权限控制管理, 然后在前端接口访问时候涉及到跨域,但我怎么配置跨域也没有生效,这里有一个坑,在使用 ...

  3. vue+springboot前后端分离实现单点登录跨域问题处理

    最近在做一个后台管理系统,前端是用时下火热的vue.js,后台是基于springboot的.因为后台系统没有登录功能,但是公司要求统一登录,登录认证统一使用.net项目组的认证系统.那就意味着做单点登 ...

  4. Springboot实现filter拦截token验证和跨域

    背景 web验证授权合法的一般分为下面几种 使用session作为验证合法用户访问的验证方式 使用自己实现的token 使用OCA标准 在使用API接口授权验证时,token是自定义的方式实现起来不需 ...

  5. Web API(五):Web API跨域问题

    一.什么是跨域问题 跨域:指的是浏览器不能执行其他网站的脚本.是由浏览器的同源策略造成的,是浏览器施加的安全限制.(服务端可以正常接收浏览器发生的请求,也可以正常返回,但是由于浏览器的安全策略,浏览器 ...

  6. 两种解决springboot 跨域问题的方法示例

    两种解决springboot 跨域问题的方法示例,哪种方法看情况而定,自己选择.社会Boolean哥,人狠话不多,直接上代码. 第一种实现方式:       此种方式做全局配置,用起来更方便,但是无法 ...

  7. 浅谈配置chrome浏览器允许跨域操作的方法

    浅谈配置chrome浏览器允许跨域操作的方法 一:(Lying人生感悟.可忽略) 最近有一天,对着镜子,发现满脸疲惫.脸色蜡黄.头发蓬松.眼神空洞,于是痛诉着说生活的不如意,工作没激情,工资不高,一个 ...

  8. Nginx反向代理、CORS、JSONP等跨域请求解决方法总结

    由于 Javascript 同源策略的存在使得一个源中加载来自其它源中资源的行为受到了限制.即会出现跨域请求禁止. 通俗一点说就是如果存在协议.域名.端口或者子域名不同服务端,或一者为IP地址,一者为 ...

  9. spring mvc \ spring boot 允许跨域请求 配置类

    用@Component 注释下,随便放个地方就可以了 package com.chinaws.wsarchivesserver.core.config; import org.springframew ...

  10. Web Api跨域访问配置及调用示例

    1.Web Api跨域访问配置. 在Web.config中的system.webServer内添加以下代码: <httpProtocol> <customHeaders> &l ...

随机推荐

  1. 解决Revit导出FBX模型材质丢失的问题

    初次使用Revit导出fbx格式模型,在导出模型后发现模型材质丢失了,上网查询之后也没到具体原因是什么,不过倒是找到了解决方式:在Revit中安装naviswork插件,然后从revit中导出nwc格 ...

  2. Vue学习笔记之组件与通信

    1. 组件 1.1. 什么是组件 组件是可复用的Vue实例, 说白了就是一组可以重复使用的模板,通常一个应用会以一棵嵌套的组件树的形式来组织: 例如,你可能会有页头.侧边栏.内容区等组件,每个组件又包 ...

  3. Python ( 高级 第一部)

    目录 time 时间模块 Python的内置方法 数字模块 随机模块 序列化模块 pickle 序列化模块 json os 系统模块 os  shutil 模块 os,path 模块 文件压缩模块 z ...

  4. 【Direct3D 12】配置编译环境

    创建桌面应用程序 使用Visual Studio Community 2019创建一个桌面应用程序. 配置SDK版本.头文件.依赖库 右键单击创建的项目名称,选择Properties. 在Config ...

  5. Django中遇到的问题

    1.如右上角无Dj的 Django标识 解决方法1: 关闭Pycharm 重启创建项目,进入到Django的所在目录下 解决方法2: 方法3: 第一步: 第二步: 第三步: 第四步: 2.如下图:显示 ...

  6. transformers 之Trainer对应的数据加载

    基础信息说明 本文以Seq2SeqTrainer作为实例,来讨论其模型训练时的数据加载方式 预训练模型:opus-mt-en-zh 数据集:本地数据集 任务:en-zh 机器翻译 数据加载 Train ...

  7. golang 字符串函数

    1. 统计字符串的长度,按字节进行统计 package main import "fmt" func main() { var s1 string = "hello,世界 ...

  8. 2022-05-26内部群每日三题-清辉PMP

    1.在执行关键路径上的一项活动时,职能主管将涉及这个活动的两个项目资源调去支持解决某个应急情况,项目经理应该怎么做? A.实施应急计划 B.快速跟进关键路径 C.与职能经理协商分配替代资源 D.将该问 ...

  9. kubernetes 集群部署问题点统计

    1.安装网络插件报错 error unable to recognize "calico.yaml": no matches for kind "DaemonSet&qu ...

  10. 使用stream流对数据进行处理

    1. 使用场景 本次使用是通过条件查询出所需要的多个字段后,对其进行处理(一个条件查询多个下拉框内容,并对每个下拉框内容封装对象,进行返回) 2. 代码 点击查看代码 //获取所有需要的数据 List ...