Springboot +spring security,解决跨域问题

news2024/11/28 10:48:58

一.简介

这篇文章主要是解释什么是跨域,在Spring中如何解决跨域,引入Spring Security后Spring解决跨域的方式失效,Spring Security 如何解决跨域的问题。

二.什么是跨域

跨域的概率:

浏览器不能执行其他网站的脚本,从一个域名的网页去请求另一个域名的资源时,域名、端口、协议任一不同,都是跨域。跨域是由浏览器的同源策略造成的,是浏览器施加的安全限制。a页面想获取b页面资源,如果a、b页面的协议、域名、端口、子域名不同,所进行的访问行动都是跨域的。

三.演示跨域

3.1创建项目

如何创建一个SpringSecurity项目,前面文章已经有说明了,这里就不重复写了。

3.2后端接口

代码如下:

@RequestMapping
@RestController
public class IndexController {
    @PostMapping("/cors")
    public String hello() {
        return "hello";
    }
}

3.3前端页面

代码如下:

<!DOCTYPE html>
<html>
 <head>
  <meta charset="utf-8" />
  <title></title>
  <!-- <script src="https://unpkg.com/vue@next"></script> -->
  <script src="js/v3.2.8/vue.global.prod.js" type="text/javascript" charset="utf-8"></script>
  <script src="https://unpkg.com/axios/dist/axios.min.js"></script>
 </head>
 <body>
  <div id="app">
   <button @click="sendCorsRequest">发起跨域请求</button>
  </div>
  <script>
   const App = {
    data() {
     return {
     }
    },
    methods: {
     sendCorsRequest() {
      axios.post('http://localhost:8080/cors', {
       firstName: 'Fred',
       lastName: 'Flintstone'
      })
      .then(function (response) {
       console.log(response)
      })
      .catch(function (error) {
       console.log(error);
      });
     }
    },
    
   };
   Vue.createApp(App).mount('#app');
  </script>
 </body>
</html>

3.4演示

打开页面,截图如下:
在这里插入图片描述
点击按钮,发送跨域请求,最终也发生了跨域请求,截图如下:

在这里插入图片描述

四.解决跨域

解决跨域有很多中方式,代码层面和非代码层面(nginx),这篇文章内容主讲解通过代码来解决跨域

4.1Spring 解决跨域

4.1.1Cors注解

标注在方法上,代码如下:

@RequestMapping
@RestController
public class IndexController {
    @RequestMapping("/cors")
    @CrossOrigin("http://127.0.0.1:8848")
    public String hello() {
        return "hello";
    }
}

在这里插入图片描述

标注在类上,代码如下:

@RequestMapping
@RestController
@CrossOrigin("http://127.0.0.1:8848")
public class IndexController {
    @RequestMapping("/cors")
    public String hello() {
        return "hello";
    }
}

在这里插入图片描述

4.1.2配置 CorsRegistry

代码如下:

@Configuration
public class WebMVCConfig implements WebMvcConfigurer {
    @Override
    public void addCorsMappings(CorsRegistry registry) {
        registry.addMapping("/cors")
                .allowCredentials(false)
                .allowedHeaders("*")
                .allowedMethods("POST")
                .allowedOrigins("*");
    }
}

4.1.3Cors 过滤器

代码如下:

@Configuration
public class WebMvcFilterConfig {
    @Bean
    FilterRegistrationBean<CorsFilter> cors(){
        FilterRegistrationBean<CorsFilter> registrationBean = new FilterRegistrationBean<>();
        CorsConfiguration configuration = new CorsConfiguration();
        configuration.addAllowedHeader("*");
        configuration.addAllowedMethod("*");
        configuration.addAllowedOrigin("*");
        configuration.addExposedHeader("*");
        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        source.registerCorsConfiguration("/**",configuration);
        registrationBean.setFilter(new CorsFilter(source));
        return registrationBean;
    }
}

以上三种使用spring解决跨域的方式讲解完了,接下来我们来说下如何在SpringSecurity中解决跨域。

4.2为什么在SpringSecurity中使用之前的跨域解决方案会失效

或许有好多人在项目中都碰到这个问题了,今天演示下,然后解释下为什么会出现这个问题。

4.2.1演示跨域失效

基于上面的代码,我们加上security依赖

org.springframework.boot:spring-boot-starter-security

配置securityConfig,代码如下:

 @Bean
    public SecurityFilterChain config(HttpSecurity http) throws Exception {
        http.authorizeHttpRequests()
                .anyRequest().authenticated()
                .and()
                .exceptionHandling()
           .accessDeniedHandler((req, resp, e) -> {
                    Map<String, Object> result = new HashMap<>();
                    result.put("code", -1);
                    result.put("msg", "访问失败");
                    result.put("data", e.getMessage());
                    writeResp(result, resp);})
                .and()
                .csrf().disable();

        return http.build();
    }
    public void writeResp(Object content, HttpServletResponse response) {
        response.setContentType("application/json;charset=utf-8");
        try {
            response.getWriter().println(JSON.toJSONString(content));
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

再次访问,发现还是跨域,之前的解决方案失效,截图如下:
在这里插入图片描述

4.2.3跨域解决失效的原因

为什么会失效呢,这个得要看下web中过滤器和拦截器执行顺序了,我们用一张图来看下web个组件的执行顺序。
在这里插入图片描述

  1. 首先经过过滤器,包括web filter和security filter
  2. 再经过Dispatcherservlet
  3. 再来到拦截器
  4. 最后才到controller 这样梳理下,不知道大家有没有明白点,首先理清一点,spring实现跨域解决主要是通过拦截器(两个注解实现)和过滤器,那么为什么会失效呢, 主要有以下几点
  5. security 是基于过滤器开启全路径拦截(需要拦截的),包括options请求
  6. 注解是基于拦截器实现,在security filter之后,所以options请求会被拦截,最终不起作用
  7. 过滤器方式不生效 是由于它的优先级在security filter之后,所以也会被拦截,最终不起作用

所以基于上面的分析,我们看下如何一一解决。

4.3Spring Security 跨域解决

4.3.1粗暴方式让Spring 方式生效

首先拦截器不生效,是由于请求被拦截,所以需要将请求放过去,配置如下:

@Bean
    public SecurityFilterChain config(HttpSecurity http) throws Exception {
        http.authorizeHttpRequests()
                .antMatchers("/cors").permitAll()
                .anyRequest().authenticated()
                .and()
                .exceptionHandling()
           .accessDeniedHandler((req, resp, e) -> {
                    Map<String, Object> result = new HashMap<>();
                    result.put("code", -1);
                    result.put("msg", "访问失败");
                    result.put("data", e.getMessage());
                    writeResp(result, resp);})
            .accessDeniedHandler(new AccessDeniedHandler() {
                    @Override
                    public void handle(HttpServletRequest request, HttpServletResponse response, AccessDeniedException accessDeniedException) throws IOException, ServletException {
                        Map<String, Object> result = new HashMap<>();
                        result.put("code", -1);
                        result.put("msg", "访问失败");
                        result.put("data", accessDeniedException.getMessage());
                        writeResp(result, response);
                    }
                })
                .and()
                .csrf().disable();

        return http.build();
    }

在这里插入图片描述

这种方式虽然可以,但是违背了我们业务,如果这个接口需要认证呢,所以这种方式一般用不上。

4.3.2将跨域过滤器提前于Security 过滤器

如果想让过滤器提前,仅需要设置过滤器的优先级就好,调整下代码,只需要加上一行代码: registrationBean.setOrder(Ordered.HIGHEST_PRECEDENCE); 同时移除上面的配置,代码如下:

@Bean
    FilterRegistrationBean<CorsFilter> cors(){
        FilterRegistrationBean<CorsFilter> registrationBean = new FilterRegistrationBean<>();
        CorsConfiguration configuration = new CorsConfiguration();
        configuration.addAllowedHeader("*");
        configuration.addAllowedMethod("*");
        configuration.addAllowedOrigin("*");
        configuration.addExposedHeader("*");
        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        source.registerCorsConfiguration("/**",configuration);
        registrationBean.setFilter(new CorsFilter(source));
        registrationBean.setOrder(Ordered.HIGHEST_PRECEDENCE);
        return registrationBean;
    }

在这里插入图片描述
请求成功,但是由于cors接口需要认证被拦截,但是接口已经调用成功,说明跨域已经解决

4.3.3通过.cors()解决

代码如下:

@Bean
    public CorsConfigurationSource corsConfigurationSource() {
        CorsConfiguration configuration = new CorsConfiguration();
        configuration.addAllowedHeader("*");
        configuration.addAllowedMethod("*");
        configuration.addAllowedOrigin("*");
        configuration.addExposedHeader("*");
        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        source.registerCorsConfiguration("/**", configuration);
        return source;
    }

在这里插入图片描述

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

jsp页面调试

现象: 访问jsp页面, 页面为空, 网络请求显示失败, 控制台打印错误net::ERR_INCOMPLETE_CHUNKED_ENCODING 200 分析: 错误描述&#xff1a;编码模块不完整&#xff0c;返回浏览器的流不完整 可能得原因: 1、网络是否稳定 2、服务器端是否有对响应数据做限制&#xff0c;比如…

【App自动化测试】(十七)遍历测试工具——Android Maxim

目录 1. Android Maxim介绍2. Android Maxim使用方法3.Android Maxim运行命令4.Android Maxim的策略5.实例演示——Windows系统&#xff0c;使用AVD模拟器&#xff0c;系统 Android6.0 1. Android Maxim介绍 Android Maxim是基于遍历规则的高性能Android Monkey&#xff0c;适…

基于SpringBoot+Vue的毕业生信息招聘平台设计与实现

博主介绍&#xff1a; 大家好&#xff0c;我是一名在Java圈混迹十余年的程序员&#xff0c;精通Java编程语言&#xff0c;同时也熟练掌握微信小程序、Python和Android等技术&#xff0c;能够为大家提供全方位的技术支持和交流。 我擅长在JavaWeb、SSH、SSM、SpringBoot等框架下…

Elasticsearch常用接口使用说明以及postman调用调试

查看集群状态 接口url&#xff1a;http://xxxx:9200/_cat 查看所有索引 http://xxxx:9200/_cat/indices?v 创建索引 http://xxxx:9200/test-20230526?pretty 返回值 { "acknowledged": true, "shards_acknowledged": true, "index": &quo…

Opencv-C++笔记 (2) : opencv的矩阵操作

文章目录 创建与初始化1.1 数据类型1.2 基本方法1.3 初始化方法 矩阵加减法矩阵乘法矩阵转置矩阵求逆矩阵非零元素个数矩阵均值与标准差矩阵全局极值及位置GEMM 通用矩阵乘法Transform 对数组每一个元素执行矩阵变换MulTransposed 计算数组和数组的转置的乘积Trace 返回矩阵的迹…

WIN10:Cognos10.2_x32安装

一、Cognos BI Server 10.2 32Bit 二、Cognos Transformer 10.2 三、Cognos Framework Manager 10.2 四、环境 1、如果使用Cognos自带的Tomcat web容器&#xff0c;将E:\common\Cognos\c10\webcontent下的所有文件拷贝到E:\common\Cognos\c10\webapps\p2pd 下面.(一般我们就使…

redis高级篇 缓存双写一致性之更新策略

闲聊 缓存通用查询3部曲 redis 中数据&#xff0c;返回redis 中的数据redis 中没有&#xff0c;查询数据库并返回完成第二部的同时&#xff0c;将数据库查询结果写到redis,redis和数据库数据一致. 谈谈双写一致性的理解 1.如果redis 中有数据&#xff1a;需要和数据库中的相…

什么是可视化开发平台?拥有什么优势?

随着科技的进步和发展&#xff0c;可视化开发平台拥有广阔的市场前景&#xff0c;在提升企业办公企业效率、做好数据管理等方面具有自身的特色和优势。在办公自动化发展的年代&#xff0c;低代码开发平台是助力企业实现提质增效办公效率的得力助手&#xff0c;其可视化、易操作…

Windows操作系统存储管理——实存管理和虚存管理

我是荔园微风&#xff0c;作为一名在IT界整整25年的老兵&#xff0c;今天总结一下Windows操作系统存储管理——实存管理和虚存管理。 存储器管理的对象是主存&#xff08;内存&#xff09;。重点是要知道实存和虚存的管理&#xff0c;而虚存管理重点是逻辑地址和物理地址间的转…

桥梁结构健康监测解决方案

城市桥梁担负着城市的交通和运输网络的重要角色&#xff0c;是城市生命线的重要组成部分。然而&#xff0c;随着时间的推移和日益增长的负荷&#xff0c;桥梁可能会受到各种因素的损害&#xff0c;如自然灾害、疲劳、腐蚀等。因此&#xff0c;桥梁结构健康监测变得至关重要&…

osg给osg::Geometry(自己绘制的几何体)添加纹理(二)

目录 1. 前言 2. 自会集合体贴纹理 2.1. 一张图贴到整个几何体 2.2. 几何体每个面贴不同的图片纹理 3. 说明 1. 前言 前文讲述了如何给osg自带的几何体&#xff0c;如&#xff1a;BOX等&#xff0c;添加纹理&#xff0c;文章参考链接如下&#xff1a; osg给osg::Geometry&…

6步带你弄懂敏捷软件开发管理

敏捷开发是一种项目管理和软件开发的迭代方法&#xff0c;可帮助团队较快地为客户创造价值&#xff0c;同时减少问题。为了获得好处&#xff0c;软件项目团队需要知道如何正确使用敏捷管理方法。 了解敏捷宣言 敏捷宣言阐述了基本的价值观&#xff0c;还详细说明了敏捷团队应…

【云计算与虚拟化】第五章—— vCenter Server 5.5 的高级功能(三)

第五章—— vCenter Server 5.5 的高级功能&#xff08;三&#xff09; 1.使用vsphere client 登陆vcenter服务器,创建一个群集&#xff0c;名称为自己的学号&#xff0c;&#xff08;截图&#xff09; 2.针对该群集打开HA功能&#xff08;截图&#xff09; 3.接入控制策略选择…

【Linux安装】从无到有!在VM虚拟机上安装Linux

系列文章目录 文章目录 系列文章目录准备工作1、Linux阿里云iso镜像: [Centos7.9.2009](http://mirrors.aliyun.com/centos/7.9.2009/isos/x86_64/?spma2c6h.25603864.0.0.5ec0f5adDd8whz) 一、在虚拟机上开辟空间 这里使用VM15做安装例子&#xff0c;16也同样适用1、打开VM 点…

ORB-SLAM内的卡方检验

ORB-SLAM内的卡方检验 1. 概念2. 卡方检验的基本思想3. 卡方检测示例4. ORB-SLAM2中卡方检测剔除外点的策略4.1 示例&#xff0c;卡方检验计算置信度得分: CheckFundamental()、CheckHomography() Reference: 卡方检验(Chi-square test/Chi-Square Goodness-of-Fit Test)卡方检…

chatgpt在复杂问题的回答表现

2023年东南大学论文&#xff1a;Evaluation of ChatGPT as a Question Answering System for Answering Complex Questions 代码库已经无法访问了&#xff1a;https://github.com/tan92hl/Complex-Question-Answering- Evaluation-of-ChatGPT 1.简介 复杂问题的回答&#xff…

ROS学习——在rviz中调用电脑摄像头

一、安装相关软件包 安装uvc camera sudo apt-get install ros-kinetic-uvc-camera安装image相关功能包 sudo apt-get install ros-kinetic-image-* sudo apt-get install ros-kinetic-rqt-image-view 要记得把kinetic换成 你自己的ros版本。 二、启动ros&#xff0c;调用…

我国中央商务区(CBD)的空间重构及发展模式

中央商务区&#xff08;Central Business District&#xff0c;简称为CBD&#xff09;&#xff0c;原始意义为“商业会聚之地”是指一个国家或城市商务活动的主要集中的区域&#xff0c;是汇聚商务服务、金融服务、科技服务、咨询服务、会展服务、文化服务等服务业的集聚区域&a…

科海思针对锂盐溶液/锂电废水除钙镁、除硼、除铊的解决方案

碳酸锂是锂电行业阳极生产中的一个重要原材料&#xff0c;主要用于制造钴酸锂、镍酸锂、锰酸锂等电极材料&#xff0c;在充电锂电池中也用作非水溶液电解质等&#xff0c;具有良好的电化学性能&#xff0c;应用领域还在不断扩大。 工业级碳酸锂主含量&#xff08;Li2CO3&#…

es elasticsearch 八 mapping 映射 、复杂数据类型

目录 Mapping 映射 复杂数据类型 Mapping 映射 精确匹配 必须和对应字段值安全一致才可查出 全文检索 缩写搜索全程、格式转换 大小写 同义词 全文检索核心原理 分词&#xff0c;初步的倒排索引的建立 重建倒排索引 时态转换、重复数的转换、同义词的转换、大小写的转换 …