Springboot +spring security,解决跨域问题

一.简介

这篇文章主要是解释什么是跨域,在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;
    }

在这里插入图片描述

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【新星计划-2023】TCP/IP协议讲解

相信大家在学习的过程中一定听到过TCP/IP这个协议&#xff0c;那么&#xff0c;TCP/IP协议是什么&#xff1f;为什么会有TCP/IP协议&#xff1f; 一、TCP/IP是什么&#xff1f; TCP/IP是用于计算机通信的一组协议&#xff0c;我们通常称它为TCP/IP协议族。它是70年代中期美国…

Taro 项目怎么获取元素的高度和视口高度

最近做小程序&#xff0c;用的Taro&#xff0c;需要设置空状态居中显示&#xff0c;因为空状态出现的地方不一样&#xff0c;所以需要动态设置&#xff0c;那么就需要获取元素的高度来计算 文档翻了一遍也没有找到&#xff0c;原生js获取高度得到的是null&#xff0c;百度了下…

考研数据结构--图

文章目录 图图的基本概念图的定义种类 图的抽象数据类型图的基本术语1. 端点和邻接点2. 顶点的度、入度和出度3. 完全图4. 稠密图、稀疏图5. 子图6. 路径和路径长度7. 回路或环8. 连通、连通图和连通分量9. 强连通图和强连通分量在一个图中找强连通分量的方法 10. 权和网 图的存…

自信裸辞:一晃 ,失业都3个月了.....

最近&#xff0c;找了很多软测行业的朋友聊天、吃饭 &#xff0c;了解了一些很意外的现状 。 我一直觉得他们技术非常不错&#xff0c;也走的测开/管理的路径&#xff1b;二三月份裸辞的&#xff0c;然后一直在找工作&#xff0c;现在还没找到工作 。 经过我的分析&#xff0…

2023年广东省中职网络安全Web渗透测试解析(超详细)

一、竞赛时间 180分钟 共计3小时 二、竞赛阶段 1.访问地址http://靶机IP/task1,分析页面内容,获取flag值,Flag格式为flag{xxx}; 2.访问地址http://靶机IP/task2,访问登录页面。用户user01的密码为1-1000以内的数,获取用户user01的密码,将密码作为Flag进行提交,Flag格式…

如何真正开启docker远程访问2375

注意看官方文档 Configure remote access for Docker daemon | Docker Documentation 1. windows上Docker Desktop开启远程访问端口2375 系统版本&#xff1a; win10专业版 Docker Desktop版本&#xff1a;4.18.0 很简单勾上&#xff0c; 应用并重启即可 2. linux上开启 尝…

设计模式—“接口隔离”

在组件构建过程中,某些接口之间直接的依赖常常会带来很多问题、甚至根本无法实现。采样添加一层间接(稳定)接口,来隔离本来互相紧密关联的接口是一种常见的解决方案。 典型模式有:Fascade、Proxy、Adapter、Mediator 一、Fascade 动机 上述A方案的问题在于组件的客户和…

性能测试重要知识与TPS上不去原因分析,测试进阶之路卷起来...

目录&#xff1a;导读 前言一、Python编程入门到精通二、接口自动化项目实战三、Web自动化项目实战四、App自动化项目实战五、一线大厂简历六、测试开发DevOps体系七、常用自动化测试工具八、JMeter性能测试九、总结&#xff08;尾部小惊喜&#xff09; 前言 常见性能测试术语…

音视频使用qt测试ffmpeg接口时无法运行

仅仅时把自己过程中遇到的稍微阻塞疑惑问题做出整理&#xff0c;疑惑的是拿到的ffmpeg包中没有dll文件&#xff0c;导致自己研究了一系列。 使用qt加载音视频ffmpeg对应的相关lib库&#xff0c;进行接口&#xff0c;源码的研究。 1&#xff1a;使用源码安装的方式获取相关的动…

易基因:全基因组DNA甲基化分析揭示DNMT1在斑马鱼模型听觉系统发育中的作用 | 胚胎发育

大家好&#xff0c;这里是专注表观组学十余年&#xff0c;领跑多组学科研服务的易基因。 听力障碍通常与内耳发育不全或损伤有关&#xff0c;是影响生活质量的严重健康问题。因此研究听觉器官发生过程中的关键基因对于探索听力损伤的潜在策略至关重要。斑马鱼模型在理解内耳发…

基于SSM的校园办公管理系统的设计与实现(源码完整)

项目描述 临近学期结束&#xff0c;还是毕业设计&#xff0c;你还在做java程序网络编程&#xff0c;期末作业&#xff0c;老师的作业要求觉得大了吗?不知道毕业设计该怎么办?网页功能的数量是否太多?没有合适的类型或系统?等等。这里根据你想解决的问题&#xff0c;今天给…

噶了呀,现在的00后这么卷的吗?

现在的小年轻真的卷得过分了。前段时间我们公司来了个00年的&#xff0c;工作没两年&#xff0c;跳槽到我们公司起薪20K&#xff0c;都快接近我了。 后来才知道人家是个卷王&#xff0c;从早干到晚就差搬张床到工位睡觉了。 最近和他聊了一次天&#xff0c;原来这位小老弟家里…

企业微信也能接入ChatGPT啦~你也能成功,步骤超详细~

文章目录 配置企业微信创建企业创建应用 配置项目一、OpenAI账号注册二、克隆项目代码三、复制配置文件四、企业微信配置 服务器购买运行项目安装Python安装核心依赖启动项目 个人微信绑定 上次我把ChatGPT接入了微信&#xff08;请看这篇文章当ChatGpt接入微信群之后&#xff…

前几天面了个30岁左右的测试员,年薪50w问题基本都能回答上,必是刷了不少八股文···

互联网行业竞争是一年比一年严峻&#xff0c;作为测试工程师的我们唯有不停地学习&#xff0c;不断的提升自己才能保证自己的核心竞争力从而拿到更好的薪水&#xff0c;进入心仪的企业&#xff08;阿里、字节、美团、腾讯等大厂.....&#xff09; 所以&#xff0c;大家就迎来了…

论文笔记: Trajectory Clustering: A Partition-and-Group Framework

07 Sigmoid 使用类DBSCAN的思路对轨迹聚类 1 intro 1.1 轨迹聚类 现有的轨迹聚类算法是将相似的轨迹作为一个整体进行聚类&#xff0c;从而发现共同的轨迹。 但是这样容易错过一些共同的子轨迹&#xff08;sub-trajectories&#xff09;。而在实际中&#xff0c;当我们对特…

Redis主从复制,哨兵模式和集群模式

一、主从复制 1、主从复制-哨兵-集群 主从复制&#xff1a;主从复制是高可用Redis的基础&#xff0c;哨兵和集群都是在主从复制基础上实现高可用的。主从复制主要实现了数据的多机备份&#xff0c;以及对于读操作的负载均衡和简单的故障恢复。缺陷&#xff1a;故障恢复无法自…

服务器被勒索病毒攻击怎么办,如何进行勒索病毒解密与预防工作?

在当今社会中服务器已经成为企业关键数据存储和传输的重要载体&#xff0c;同样也成为黑客攻击和勒索病毒的首要目标。一旦服务器被勒索病毒攻击&#xff0c;企业的正常运转与经济利益和核心数据都将受到威胁。下面将为大家介绍一下服务器被勒索病毒攻击后应该采取怎样的措施及…

软件系统三基座之一:权限管理

软件系统三基座包含&#xff1a;权限管理、组织架构、用户管理。 何为基座&#xff0c;即是有了这些基础&#xff0c;任一相关的“建筑”就能逐步搭建起来。 万丈高楼平地起 一、为什么要权限管理 权限管理&#xff0c;一般指根据系统设置的安全规则或者安全策略&#xff0c;…

【013】C++数组之一维数值数组和二维数值数组

一维数值数组和二维数值数组 引言一、一维数值数组1.1、概念1.2、一维数值数组的定义1.3、一维数值数组的初始化1.4、一维数值数组的元素操作1.5、使用示例 二、二维数值数组2.1、概述2.2、二维数值数组的初始化2.3、二维数值数组的元素操作2.4、使用示例 总结 引言 &#x1f4…

Windows 安装 GCC

文章目录 GCC 是什么&#xff1f;GCC 和 gcc 什么关系&#xff1f;Windows 安装 GCC选型下载安装配置环境变量验证 参考文献 GCC 是什么&#xff1f; GCC&#xff08;GNU Compiler Collection&#xff09;是一个开源的编译器套件&#xff0c;由 GNU 项目开发和维护。 GNU 编译…