SpringSecurity(十一)【跨域】

news2024/12/23 15:12:21

十一、跨域


简介

跨域问题实际应用开发中的一个非常常见的需求,在 Spring 框架中对于跨域问题的处理方案有好几种,引入了 Spring Security 之后,跨域问题的处理方案又增加了

什么是 CORS

CORS(Cross-Origin Resource-Sharing)是由 W3C 制定的一种跨域资源共享技术标准,其目的就是为了解决前端的跨域请求。在 JavaEE 开发中,最常见的前端跨域请求解决方案是早期的 JSONP,但是 JSONP 只支持GET请求,这是一个很大的缺陷,而 CORS 则支持多种 HTTP 请求方法,也是目前主流的跨域解决方案

CORS 中新增了一组 HTTP 请求头字段,通过这些字段,服务器告诉浏览器,哪些网站通过浏览器有权限访问哪些资源。同时规定,对哪些可能修改服务器数据的 HTTP 请求方法(如 GET 以外的 HTTP 请求等),浏览器必须首先使用OPTIONS方法发起一个预检请求(Pre inspection request),预检请求的目的是查看服务端是否支持即将发起的跨域请求,如果服务端允许,才发送实际的 HTTP 请求。在预检请求的返回中,服务器也可以通知客户端,是否需要携带身份凭证(如 Cookie、HTTP 认证信息等)

CORS:同源/同域 = 协议 + 主机 + 端口

简单请求

GET 请求为例,如果需要发起一个跨域请求,请求头如下

Host: locahost:8080
Origin: http://locahost:8081
Referer: http://locahost:8081/index.html

如果服务端(8080)支持该跨域请求,那么返回响应头中将包含如下字段

Access-Control-Allow-Origin: http://locahost:8081

Access-Control-Allow-Origin 字段用来告诉浏览器可以访问该资源的域,当浏览器收到这样的响应头信息之后,提取出Access-Control-Allow-Origin字段中的值,发现该值包含当前页面所在域,就知道这个域是被允许的,因此就不再对前端的跨域请求进行限制。这个属于简单请求,即不需要进行预检请求的跨域

非简单请求

对于一些非简单请求,会首先发送一个与检验请求。预检请求类似下面这样

OPTIONS /put HTTP/1.1
Host: locahost:8080
Connection: keep-alive
Accept: */*
Access-Control-Request-Method: PUT
Origin: http://localhost:8081
Referer: http://localhost:8081/index.html

请求方法是OPTIONS,请求头 Origin 就告诉服务端当前页面所在域,请求头Access-Control-Request-Methods告诉服务器即将发起的跨域请求所使用的方法。服务端对此进行判断,如果允许即将发起的跨域请求,则会给出如下响应

HTTP/1.1 200
Access-Control-Allow-Origin: http://localhost:8081
Access-Control-Request-Methods: PUT
Access-Control-Max-Age: 3600
  • Access-Control-Request-Methods:表示允许的跨域方法
  • Access-Control-Max-Age:表示预检请求的有效期,单位为秒。在有效期内如果发起该跨域请求,则不用再次发起预检请求。预检请求结束后,接下来就会发起一个真正的跨域请求,跨域请求和前面简单请求跨域步骤类似

11.1 Spring 跨域解决方案

方式一:@CrossOrigin

Spring 中第一种处理跨域的方式是通过@CrossOrigin注解来标记支持跨域,该注解可以添加在方法上,也可以添加在 Controller 上。当添加在 Controller 上时,表示 Controller 中的所有接口都支持跨域。具体配置如下

@RestController
public class TestController {

    @GetMapping("/cors")
    @CrossOrigin(origins = "http://127.0.0.1:8081")
    public String testCors() {
        return "Hello Cors!";
    }
}

在这里插入图片描述

@CrossOrigin注解个属性含义如下

  • allowCredentials:浏览器是否应当发送凭证信息,如 Cookie(字符串)
  • allowedHeaders:请求被允许的请求头字段,*表示所有字段(字符串数组)
  • exposedHeaders:哪些响应头可以作为相应的一部分暴露出来(字符串数组)
    • 】这里可以一一列举,通配符*在这里是无效的
  • maxAge:预检请求的有效期,有效期内不必再次发送预检请求,默认是1800
  • methods:允许的请求方法,*表示允许所有方法(请求方法数组)
  • origins:允许的域,*表示允许所有域(字符串数组)

方式二:addCrosMapping

@CrossOrigin 注解需要添加在不同的 Controller 上。所以还有一种全局配置方法,就是通过重写 WebMvcConfigurer#addCorsMappings() 方法实现,具体配置如下

package com.vinjcent.config;

import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

@Configuration
public class WebMvcConfiguration implements WebMvcConfigurer {

    // 用来全局处理跨域
    @Override
    public void addCorsMappings(CorsRegistry registry) {
        registry.addMapping("/**")  // 对哪些请求进行跨域
                .allowedMethods("*")
                .allowedOrigins("*")
                .allowedHeaders("*")
                .maxAge(3600);
    }
}

方法三:CorsFilter

CorsFilter 是 Spring Web 中提供的一个处理跨域的过滤器,开发者也可以通过该过滤器处理跨域

package com.vinjcent.filter;

import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
import org.springframework.web.filter.CorsFilter;

import java.util.Arrays;

@Configuration
public class WebMvcFilter {

    @Bean
    public FilterRegistrationBean<CorsFilter> corsFilter() {
        // 1.定义需要注册的过滤器bean
        FilterRegistrationBean<CorsFilter> registrationBean = new FilterRegistrationBean<>();
        // 2.定义跨域配置信息
        CorsConfiguration corsConfiguration = new CorsConfiguration();
        corsConfiguration.setAllowedHeaders(Arrays.asList("*"));
        corsConfiguration.setAllowedMethods(Arrays.asList("*"));
        corsConfiguration.setAllowedOrigins(Arrays.asList("*"));
        corsConfiguration.setMaxAge(3600L);

        // 3.定义过滤器生效的url配置
        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        source.registerCorsConfiguration("/**", corsConfiguration);
        registrationBean.setFilter(new CorsFilter(source));
        registrationBean.setOrder(-1);  // 一般是0、1,代表过滤器顺序等级,-1代表优先


        return registrationBean;
    }
}

11.2 Spring Security 跨域解决方案

原理分析

当我们为项目添加了 Spring Security 依赖之后,发现上面三种跨域方式有的失效,有的则可以继续使用

通过@CorsOrigin注解或者重写 addCorsMappings 方法配置跨域,统统失效,通过 CorsFilter 配置的跨域,有没有失效则要看过滤器的优先级。如果过滤器优先级高于 Spring Security 过滤器,即先于 Spring Security 过滤器执行,则 CorsFilter所配置的跨域处理依然有效;如果过滤器优先级低于 Spring Security 过滤器,则 CorsFilter 所配置的跨域处理就会失效

为了理清楚这个问题,我们先简略了解一下 Filter、DispatcherServlet 以及 Interceptor 执行顺序

在这里插入图片描述

理解清楚了执行顺序之后,我们再来看跨域请求过程。由于非简单请求首先发送一个预检请求Pre inspection request),而预检请求并不会携带认证信息,所以预检请求就有被 Spring Security 拦截的可能。因此通过@CorsOrigin注解或者重写 addCorsMappings() 方法配置跨域就会失效。如果使用 CorsFilter 配置的跨域,只要过滤器优先级高于 Spring Security 过滤器就不会有问题,反之同样会出现问题

解决方案

Spring Security 中也提供了更专业的方式来解决预检请求所面临的问题,如

package com.vinjcent.config.security;

import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.CorsConfigurationSource;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;

import java.util.Arrays;

/**
 * 自定义 Security 配置
 * 在 springboot 2.7.x 后,WebSecurityConfigurerAdapter 配置不再存在
 */
@Configuration
public class WebSecurityConfiguration extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        // 所有请求都需要认证
        http.authorizeRequests()
                .anyRequest()
                .authenticated();

        // 开启登录请求
        http.formLogin();

        // 解决跨域请求
        http.cors()
                .configurationSource(configurationSource());

        // 关闭 csrf 跨域请求伪造攻击
        http.csrf()
                .disable();
    }

    // 跨域请求配置
    public CorsConfigurationSource configurationSource() {
        // 1.定义跨域配置信息
        CorsConfiguration corsConfiguration = new CorsConfiguration();
        corsConfiguration.setAllowedHeaders(Arrays.asList("*"));
        corsConfiguration.setAllowedMethods(Arrays.asList("*"));
        corsConfiguration.setAllowedOrigins(Arrays.asList("*"));
        corsConfiguration.setMaxAge(3600L);

        // 2.定义过滤器生效的url配置
        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        source.registerCorsConfiguration("/**", corsConfiguration);

        return source;
    }
}

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

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

相关文章

联合证券|重磅数据出炉,道指飙涨700点!美股新年首周“开门红”!

美股涨嗨了&#xff01; 当地时间1月6日&#xff0c;最新发布的美国12月非农工作陈述显现&#xff0c;美国工作市场终于呈现降温迹象&#xff0c;过去一年的激进加息成效初显。受此提振&#xff0c;美股三大股指高开高走&#xff0c;彻底改变前几日的跌势。从周k线看&#xff…

PCB结构和谐振(三)

PCB结构和谐振&#xff08;一&#xff09;PCB结构和谐振&#xff08;二&#xff09;仿真研究在本节中&#xff0c;我们首先对玻璃束的随机分布进行了简单的模拟研究。然后我们利用这些实验结论来简化常用的玻璃布3D结构。最后&#xff0c;这种简化的结构用于研究复杂层压板和两…

Java设计模式中原型模式是啥/浅克隆与深克隆又是什么/clone方法怎么回事

继续整理记录这段时间来的收获&#xff0c;详细代码可在我的Gitee仓库SpringBoot克隆下载学习使用&#xff01; 4.5 原型模式 4.5.1 概述 用已创建实例作为原型&#xff0c;通过复制该原型对象来创建一个和原型对象一样的新对象 4.5.2 结构 抽象原型类&#xff1a;规定具体…

Docker系列 深度使用nextcloud(九) 硬盘挂载

转自我的个人博客https://blognas.hwb0307.com&#xff0c;该文的内容更新仅在个人博客可见。欢迎关注&#xff01; 前言 基于《Docker系列 搭建个人云盘服务nextcloud》&#xff0c;相信无论是在有/无443端口的Linux机子里均可成功安装Nextcloud。值得一提的是&#xff0c;Ne…

02、做点准备工作 osg\openscenegraph源代码下载 C++三维视频融合实战系列(时空克隆)

首先&#xff0c;要有一点C编程基础&#xff0c;熟悉VS2013开发环境。 在开始实践之前&#xff0c;先要搭建号VS2013开发环境。 然后&#xff0c;建议电脑安装windows 10 64位操作系统。 接下来需要在以下地址下载开源代码&#xff1a; 1、osg下载 打开openscenegraph主页…

CSS权威指南(七)视觉格式化

文章目录1.盒模型2.元素的显示方式3.行内元素1.盒模型 不管是什么元素,CSS都假定每个元素会生成一个或多个矩形框,我们称之为元素。各元素框的中心是内容区域&#xff0c;四周有可选的内边距、边框、轮廓和外边距。默认情况下&#xff0c;内容区的背景出现在内边距范围内。外边…

5分钟搞懂用户态,内核态

5分钟搞懂用户态,内核态 1. 什么是用户态,内核态 用户态就是提供应用程序运行的空间&#xff0c;为了使应用程序访问到内核管理的资源例如CPU&#xff0c;内存&#xff0c;I/O。内核必须提供一组通用的访问接口&#xff0c;这些接口就叫系统调用。 用户态&#xff0c;内核态…

进制详解:二进制、八进制和十六进制

进制详解&#xff1a;二进制、八进制和十六进制 背景&#xff08;Contexts&#xff09; 我们平时使用的数字都是由 0~9 共十个数字组成的&#xff0c;例如 1、9、10、297、952 等&#xff0c;一个数字最多能表示九&#xff0c;如果要表示十、十一、二十九、一百等&#xff0c;…

机器学习笔记之深度信念网络(一)背景介绍与模型表示

机器学习笔记之深度信念网络——背景介绍与模型表示引言深度信念网络场景构建深度信念网络的联合概率分布引言 从本节开始&#xff0c;将介绍深度信念网络。 深度信念网络 深度信念网络(Deep Belief Network,DBN)是杰弗里辛顿(Geoffrey Hinton)于2006年提出的模型&#xff0…

Day853.WorkerThread模式 -Java 性能调优实战

WorkerThread模式 Hi&#xff0c;我是阿昌&#xff0c;今天学习记录的是关于WorkerThread模式的内容。 Thread-Per-Message 模式&#xff0c;对应到现实世界&#xff0c;其实就是委托代办。这种分工模式如果用 Java Thread 实现&#xff0c;频繁地创建、销毁线程非常影响性能…

场景编程集锦 - 吉米的总统梦想

1. 场景描述 吉米是太平洋岛国一个贫苦家庭的孩子&#xff0c;他的梦想就是当总统&#xff0c;引领国家走向富强之路。 开学的第一堂课上&#xff0c;老师用白色的粉笔在黑板上写下了“我的梦想”&#xff0c;同学们都陷入了思考。大卫的梦想是当一名科学家&#xff0c;用奇思妙…

CSS初级教程(文本)【第六天】

文章目录【1】CSS 文本[字体颜色|背景色]【2】CSS 文本对齐【3】CSS 文字装饰【4】CSS 文本转换[大写或小写]【5】CSS 文字间距【6】CSS 文本阴影【7】所有 CSS 文本属性CSS上回学习链接 CSS初级教程 颜色【第一天】 CSS初级教程 背景【第二天】 CSS初级教程 边框【第三天】 CS…

Windows访问控制 -- SID

Windows访问控制是一个比较大的题目&#xff0c;因此计划用一系列的文章简单谈一下这个。本篇是开篇&#xff0c;介绍SID。 Windows访问控制定义 Windows访问控制的含义可以参考MSDN的描述&#xff1a;Access control refers to security features that control who can acce…

Java集合容器介绍

Java 容器分为 Collection 和 Map 两大类&#xff0c;其下又有很多子类&#xff0c;如下所示&#xff1a; Collection接口&#xff1a;单列数据&#xff0c;定义了存取一组对象的方法的集合 1、List&#xff1a;元素有序(指的是存储时&#xff0c;与存放顺序保持一致)、可重复的…

【Docker】(四)使用volume持久化Docker容器中的Redis数据

1.前言 本系列文章记录了从0开始学习Docker的过程&#xff0c;Docker系列历史文章&#xff1a; &#xff08;一&#xff09;基本概念与安装使用 &#xff08;二&#xff09;如何使用Docker发布一个SpringBoot服务 &#xff08;三&#xff09;使用registry远程镜像仓库管理镜像…

[ 数据结构 ] 赫夫曼编码--------数据、文件压缩解压

0 引出 如上图:给定字符串按定长编码处理,最终对应二进制长度为359 思考:如何压缩,将359有效降低? ----回顾:赫夫曼树 1 数据压缩 拿到数据(字符串)的第一反应,虽然知道应该也像上面一样转为字节数组,但就不知道该怎么办了?统计数组中各字节使用的次数,将次数作为权值,字节…

2023.1.8 学习周报

文章目录摘要文献阅读1.题目2.摘要3.介绍4.论文主要贡献5.相关工作5.1 序列感知的推荐系统5.2 神经注意模型6.模型&#xff1a;ATTREC6.1 序列推荐6.2 基于Self-Attention的用户短期兴趣建模6.3 用户长期兴趣建模6.4 模型学习7.实验7.1 数据集7.2 评估指标7.3 模型比较7.4 实验…

SSO单点登录实例详解(前端传Code授权登录)

什么是 SSO&#xff08;单点登录&#xff09; SSO 英文全称 Single Sign On&#xff0c;单点登录。SSO 是在多个应用系统中&#xff0c;用户只需要登录一次就可以访问所有相互信任的应用系统。 单点登录流程 单点登录大致流程如下所示&#xff1a; 单点登录详细流程&#x…

【自学C++】C++变量初始化

C变量初始化 C变量初始化教程 变量 的初始化就是在定义变量的同时&#xff0c;给变量设置一个初始值&#xff0c;在 C 中&#xff0c;如果定义变量没有初始化&#xff0c;那么变量有可能会被赋值也有可能不会赋值。 如果是定义的 全局变量 或者 静态变量&#xff0c;未初始化…

2022年语音合成(TTS)和语音识别(ASR)年度总结

论文统计每月更新一次&#xff0c;主要跟踪语音合成和语音识别的发展状况(很多文章都是在会议后才发出&#xff0c;但不影响统计。统计过程难免存在疏漏&#xff0c;因此统计结果仅供参考。所有文章语音合成领域统计列表请访问http://yqli.tech/page/tts_paper.html&#xff0c…