3、SpringBoot 解决跨域问题

news/2023/5/28 8:51:48

跨域资源共享(CORS)是前后端分离项目中常见的问题,它允许浏览器向跨源服务器发送XMLHttpRequest请求,这样就克服了ajax只能同源使用限制,而同源策略的限制主要是为了避免浏览器受到 XSS、CSFR 等的攻击。

跨域

当浏览器发出请求时,出现了下面任意一种情况,都可以视为跨域问题:

  • 协议不同:比如 http 和 https。
  • 域名不同:比如主域名和子域名。
  • 端口号不同。

比如,当前页面地址为http://www.xxw.com:8080/,而被请求页面地址为 https://www.xxw.com:8080/、https://blog.xxw.com:8080/、https://www.aaa.com:8080/、https://www.xxw.com:8888/ 等都属于跨域访问。

CORS(Cross-Origin Resource Sharing)是一种跨域资源共享技术方案,它支持多种 HTTP 请求方法,请求方法的不同,在处理上也有所不同。

1、简单请求

浏览器直接发送请求,并在请求头中增加一个 Origin 字段指定页面的域,如果服务端支持该跨域请求的话,则会在响应头返回 Access-Control-Allow-Origin 字段来告诉浏览器哪些域可以请求该资源,后边浏览器会根据该字段的值决定是否限制跨域请求。

当满足以下条件时,属于简单请求:

  • 只能有 GET、POST、HEAD 三种请求方式;
  • 请求头限制这几种字段:Accept、Accept-Language、Content-Language、Content-Type、Last-Event-ID;
  • Content-type只能取:application/x-www-form-urlencoded、multipart/form-data、text/plain。

2、复杂请求

当满足以下条件时,属于复杂请求:请求方法是 PUT、DELETE,或 Content-Type 类型是 application/json。

这些跨域请求会在正式发送前先发送一次 OPTIONS 类型的预检请求,预检请求头 Origin 用来指定发送请求的浏览器页面的域、Access-Control-Request-Method 用来指定跨域请求类型;服务端如果允许该跨域请求则会在响应头返回对应的字段 Access-Control-Allow-Origin、Access-Control-Allow-Method(允许跨域的请求类型)、Access-Control-Max-Age(预检请求的有效期,单位秒),预检请求完成后的就会发送真正的请求,与简单请求的步骤基本一致。

CORS 是目前解决前端跨域请求的主流方案,它支持多种 HTTP 请求方法,SpringBoot 解决跨域问题正是基于 CORS 的后端解决方案,下面进行介绍说明。

SpringBoot 解决跨域方案

1、使用 @CrossOrigin 注解

如果该注解用在控制器类上,则该控制器中的所有接口都支持跨域;如果用在指定接口上,则该接口支持跨域访问。

示例如下:

//origins:允许的域,* 表示所有,也可指定具体的域
@CrossOrigin(origins = "*")
@RestController
public class TestController {//@CrossOrigin(origins = "*")@GetMapping("/test")public String test() {return "test,test";}
}

该注解属于局部跨域配置,当有多个控制器类或多个指定接口需要跨域配置时,缺点也很明显,会做许多重复的配置操作,无法全局配置。

2、使用基于 WebMvcConfigurer 的配置类

使用基于 WebMvcConfigurer 的配置类,重写 addCorsMappings 方法,示例如下:

@Configuration
public class CorsConfig implements WebMvcConfigurer {@Overridepublic void addCorsMappings(CorsRegistry registry) {registry.addMapping("/**").allowedOriginPatterns("*").allowCredentials(true).allowedMethods("GET", "POST", "PUT", "DELETE", "OPTIONS").maxAge(3600L);}
}

部分属性说明:

  • addMapping:可被跨域请求的接口,/**表示所有;
  • allowedOrigins:允许的域,* 表示所有,也可指定具体的域;
  • allowCredentials:是否允许浏览器发送凭证信息,例如 Cookie;
  • allowedMethods:允许的请求方法(GET、POST ... );
  • allowedHeaders:允许的请求头字段,* 表示所有;
  • exposedHeaders:哪些响应头可以作为响应的一部分暴露出来;
  • maxAge: 预检请求的有效期,有效期内不用再发出预检请求。

这种方式和上面的 @CrossOrigin 注解方式配置属性和执行原理大致相似,在 DispatcherServlet 中触发跨域处理,配置了一个 CorsConfiguration 对象,然后用该对象创建 CorsInterceptor 拦截器,然后在拦截器中调用 DefaultCorsProcessor#processRequest 方法,完成对跨域请求的校验。

3、使用跨域过滤器 CorsFilter

由于过滤器的执行时机早于拦截器,使用 CorsFilter 过滤器方式处理跨域的时机早于前两种方式,示例如下:

@Configuration
public class CorsFilterConfig {@Beanpublic CorsFilter corsFilter() {//跨域配置CorsConfiguration config= new CorsConfiguration();config.setAllowCredentials(true);config.setAllowedMethods(Collections.singletonList("*"));config.setAllowedHeaders(Collections.singletonList("*"));config.setAllowedOrigins(Collections.singletonList("*"));config.setMaxAge(3600L);//添加地址映射UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();source.registerCorsConfiguration("/**", config);//加入CorsFilter对象中CorsFilter filter = new CorsFilter(source);return filter;}}

执行机制,在跨域过滤器的 doFilterInternal 方法中调用  DefaultCorsProcessor#processRequest 方法,完成对跨域请求的校验;核心的配置和前两种方式相似,这里由 CorsConfiguration 来完成。

4、 Spring Security 引起的跨域失效问题

如果项目里引入了 Spring Security,则会导致第一种和第二种跨域方案失效,原因是 Spring Security 是基于过滤器的实现的(本质是 FilterChainProxy),而过滤器执行时机会早于拦截器,从而导致复杂请求的预检请求(OPTIONS)被 Spring Security 拦截了。因此,使用了 Spring Security 后不建议再使用这两种跨域解决方案。

同理,如果跨域过滤器 CorsFilter 设置的优先级低于 FilterChainProxy(默认100) 则使用 CorsFilter 方式也会失效。因此,我们可以设置 CorsFilter 的优先级高点(如Ordered.HIGHEST_PRECEDENCE),这样使用 Spring Security 就不会影响到 CorsFilter 了。

改造下第三种方式的代码即可,示例如下:

FilterRegistrationBean<CorsFilter> registrationBean = new FilterRegistrationBean<>();
registrationBean.setFilter(filter);
registrationBean.setOrder(Ordered.HIGHEST_PRECEDENCE);
return registrationBean;

5、 Spring Security 优雅的跨域解决方案

当然,在 Spring Security 中已经提供了更加优雅的跨域解决方案,不必为前面的失效问题考虑。

配置类的示例如下:

@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {@Overrideprotected void configure(AuthenticationManagerBuilder auth) throws Exception {InMemoryUserDetailsManager manager = new InMemoryUserDetailsManager();manager.createUser(User.withUsername("xxwei").password("123456").roles("admin").build());auth.userDetailsService(manager);}@Overrideprotected void configure(HttpSecurity http) throws Exception {http.authorizeRequests()
//                .antMatchers(HttpMethod.OPTIONS).permitAll() // 放行 @CrossOrigin、addCorsMappings 的预检请求.anyRequest().authenticated().and().httpBasic().and().formLogin()
//                .loginPage("/login").loginProcessingUrl("/doLogin").successHandler((httpServletRequest, httpServletResponse, authentication) -> {User user = (User) authentication.getPrincipal();writeMessage(httpServletResponse, new ObjectMapper().writeValueAsString(user));System.out.println("login success");}).failureHandler((httpServletRequest, httpServletResponse, e) -> {System.out.println("login failure");}).permitAll().and().logout().logoutSuccessHandler((httpServletRequest, httpServletResponse, authentication) -> {System.out.println("logout success");}).permitAll().and().exceptionHandling().authenticationEntryPoint((request, response, authException) -> {response.setStatus(401);writeMessage(response, "please login");System.out.println("please login");}).and().cors().configurationSource(corsConfigurationSource()) // Spring Security 的跨域配置.and().csrf().disable();}CorsConfigurationSource corsConfigurationSource() {CorsConfiguration config = new CorsConfiguration();config .setAllowedMethods(Collections.singletonList("*"));config .setAllowedHeaders(Collections.singletonList("*"));config .setAllowedOrigins(Collections.singletonList("*"));config .setAllowCredentials(true);config .setMaxAge(3600L);UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();source.registerCorsConfiguration("/**", config);return source;}private void writeMessage(HttpServletResponse response, String message) throws IOException {response.setContentType("application/json;charset=utf-8");PrintWriter out = response.getWriter();out.write(message);out.flush();out.close();}
}

配置看上去很多,真正和跨域相关的配置只有 .and().cors().configurationSource(corsConfigurationSource()) 一段代码,其中 corsConfigurationSource 方法的配置和 CorsFilter 方式中的相似。

以上就是 SpringBoot 解决跨域问题的方案说明, 在此记录下。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.exyb.cn/news/show-4555319.html

如若内容造成侵权/违法违规/事实不符,请联系郑州代理记账网进行投诉反馈,一经查实,立即删除!

相关文章

【013】如何给EXCEL编写的宏设置打开密码_#VBA

设置宏密码1 为什么设置密码&#xff1f;1.1 提前设好触发条件1.2 通过视窗进行触发时需要输入密码2 设置密码1 为什么设置密码&#xff1f; 当编写的宏没有问题&#xff0c;却不想被别人看&#xff0c;可以设置好密码&#xff0c;别人只需要根据提前预设的要求&#xff0c;运…

【Unity开发小技巧】Unity随机概率扩展(概率可调控)

做了以下两张图有助于理解&#xff0c;如果想调控概率的话直接修改概率数组即可&#xff0c;实战案例&#xff1a;http://t.csdn.cn/P9QKJ 其实在做概率类相关的界面效果的时候&#xff0c;我们真实做法都是在刷新界面前已经把结果获取到了&#xff0c;然后根据结果去处理界面…

4-Spring使用

目录 1.存储Bean对象到Spring容器中 1.1.创建Bean 1.2.将Bean注册到Spring容器中 1.2.1.第一次存储Bean&#xff08;可选&#xff0c;如果是第二次及以后&#xff0c;此步骤忽略&#xff09; 1.2.2.添加Bean标签 2.从Spring容器中获取并使用Bean对象 2.1.创建Spring上下…

面试概率题目

概率题目 现在的面试中,大部分公司都会问道概率相关的问题,我们现在给出几道常见的概率问题. 1. 三角形问题 题目: 给你一根铅笔,将铅笔折两次,组成三角形的概率是多大. 解析: 设: 铅笔长度是1, 折两次之后,得到三条边,对应的长度分别是x,y,1-x-y. 1. 得到条件: 0 < x <…

【概率笔记】这些概率公理性质你需要会的呀

导读 概率论是AI的基础学科&#xff0c;如果想学的深的话&#xff0c;概率论必不可少的一门呀&#xff01;概率基础还没有看的小伙伴们&#xff0c;可以看下面的链接啦&#xff1a; 【概率论】基础之概率概论与集合论 今天的主要内容为概率的一些基本公理以及它的证明和应用…

java中奖概率_java实现抽奖概率类

本文实例为大家分享了java实现抽奖概率类的具体代码&#xff0c;供大家参考&#xff0c;具体内容如下在一些项目需求中&#xff0c;可能会遇到抽奖问题&#xff0c;如提供一系列奖品及获奖概率&#xff0c;要求根据概率返回每次抽到的奖品。以下是本人在实际项目中写的一个抽奖…

js 随机取值 概率随机取值

Math.floor()为向下取整 Math.random() 一个浮点型伪随机数字&#xff0c;在0&#xff08;包括0&#xff09;和1&#xff08;不包括&#xff09;之间。 得到一个两数之间的随机数 这个值不小于 min&#xff08;有可能等于&#xff09;&#xff0c;并且小于&#xff08;不等于&…

百度大脑助力药企与医院业务智能化对接

价值成果 佐力百草在接入百度iOCR通用版技术后&#xff0c;轻松为药企和医院业务实现了智能化对接。不仅大幅降低了人工录入处方的成本&#xff0c;还提高了工作效率&#xff0c;真正为人工录入减少误差率。 案例故事 核心诉求 中药代煎中心有大部分业务是需要通过传真机来接…

百度Paddle飞桨教程

计算机视觉&#xff1a;https://www.paddlepaddle.org.cn/tutorials/projectdetail/1515319 计算机视觉作为一门让机器学会如何去“看”的学科&#xff0c;具体的说&#xff0c;就是让机器去识别摄像机拍摄的图片或视频中的物体&#xff0c;检测出物体所在的位置&#xff0c;并…

医疗信息化

22家中国医疗信息化企业上榜&#xff01;CB Insights首次发布该领域榜单 2020-07-17 14:56 新兴技术的发展&#xff0c;正在让医疗焕发出新的活力。人工智能、大数据等&#xff0c;正在通过赋能诊断流程、影像、制药、随访等环节&#xff0c;让智能医疗愈加可能。 从数字化到…

百度ERNIE新突破 登顶中文医疗信息处理权威榜单CBLUE冠军

医疗领域存在大量的专业知识和医学术语&#xff0c;人类经过长时间的学习才能成为一名优秀的医生。那机器如何才能“读懂”医疗文献呢&#xff1f;尤其是面对电子病历、生物医疗文献中存在的大量非结构化、非标准化文本&#xff0c;计算机是无法直接使用、处理的。这就需要自然…

百度飞桨:ERNIE 3.0 、通用信息抽取 UIE、paddleNLP的安装使用[一]

相关文章&#xff1a; 基础知识介绍&#xff1a; 【一】ERNIE&#xff1a;飞桨开源开发套件&#xff0c;入门学习&#xff0c;看看行业顶尖持续学习语义理解框架&#xff0c;如何取得世界多个实战的SOTA效果&#xff1f;_汀、的博客-CSDN博客_ernie模型 百度飞桨&#xff1a…

一致性哈希算法之Pastry协议总结

参考:[1]于忠涛,刘兴伟.Pastry网络模型的路由机制及改进[J].西华大学学报(自然科学版),2006(01):27-302.&#xff08;这篇论文基本上是原著英文版的中文精简版了&#xff09;

分布式计算、云计算与大数据第六章

P2P概述 P2P&#xff0c;即Peer-to-Peer的缩写&#xff0c;也称“点对点”或“端对端”&#xff0c;学术上常称为“对等计算”。P2P是一种以非集中化方式使用分布式资源来完成一些关键任务的系统和应用。P2P与目前网络中占据主导地位的客户/服务器体系架构相对应。它表示分布式…

SAP Retail Listing – How does it work?

A. Prerequisites – SAP standard VS SAP IS Retail 1. In SAP standard, you need plant view definition to process PO or movement of the article on the plant (like good receipt, good issue). Plant data on the article master data need to be maintained. Techni

【JavaWeb】HTML零基础入门

✨哈喽&#xff0c;进来的小伙伴们&#xff0c;你们好耶&#xff01;✨ &#x1f6f0;️&#x1f6f0;️系列专栏:【JavaWeb】 ✈️✈️本篇内容:HTML基础语法详解&#xff0c;附带综合案例。 &#x1f680;&#x1f680;代码托管平台github&#xff1a;JavaWeb代码存放仓库&am…

P2P网络与区块链

提起区块链,P2P网络时不得不提的.P2P是实现区块链技术中的一种.P2P与区块链有着不可割舍的情节都具有去中心化的特质.在P2P网络中1个节点,它既可以是服务器,也可以是客户端.每个节点都是平等的.组成一个对等的网络.一般使用socket进行网络编程.这就是P2P.P2P一般存在4中网络模型…

哈希表及哈希函数研究综述

哈希表及哈希函数研究综述摘要随着信息化水平的不断提高&#xff0c;数据已经取代计算成为了信息计算的中心&#xff0c;对存储的需求不断提高信息量呈现爆炸式增长趋势&#xff0c;存储已经成为急需提高的瓶颈。哈希表作为海量信息存储的有效方式&#xff0c;本文详细介绍了哈…

Pastry学习笔记

这个笔记主要是参考CDK5和老师的教学PPT。 资源可以使用全局唯一标识符&#xff08;globally unique identifier&#xff0c;GUID&#xff09;来标识。 对等系统&#xff08;P2P&#xff09; 路由覆盖&#xff08;routing overlay&#xff09; 在对等系统中路由覆盖是一个著…

【Linux】gcc/g++编译器、make/Makefile自动化构建工具

作者&#xff1a;小卢 专栏&#xff1a;《Linux》 喜欢的话&#xff1a;世间因为少年的挺身而出&#xff0c;而更加瑰丽。 ——《人民日报》 目录 1.gcc/c的概念&#xff1a; 2.程序编译过程详解&#xff1a; 2.1程序编译过程&#xff1a; 2.…