springSecruity--->和springboot结合的跨域问题

🤦‍♂️这个是我在springboot中使用springSecruity写一个小demo时遇到的问题,记录下来🤦‍♂️

文章目录

跨域请求

什么是跨域请求,为啥会有跨域请求?👍

跨域请求,就是说浏览器在执行脚本文件的ajax请求时,脚本文件所在的服务地址和请求的服务地址不一样。说白了就是ip、网络协议、端口都一样的时候,就是同一个域,否则就是跨域。这是由于Netscape提出一个著名的安全策略------同源策略造成的,这是浏览器对JavaScript施加的安全限制。是防止外网的脚本恶意攻击服务器的一种措施。

俺们先来看看请求又有哪几种吧:

1.简单请求:
简单请求是指符合跨域请求规范中定义的一种简单请求类型。简单请求必须满足以下条件:

请求方法限于 GET、POST 或 HEAD;

只能使用以下几种 Content-Type:application/x-www-form-urlencoded、multipart/form-data、text/plain;

请求中的任意 XMLHttpRequestUpload 对象均没有注册任何事件监听器;

请求中没有使用 ReadableStream 对象;

请求中的任意 ReadableStream 对象均没有被启动;

请求的 method 属性不是 GET、HEAD 或 POST 以外的字符串;

请求的带有信函头之一。

简单请求不会触发预检请求(OPTIONS 请求),而是直接发送实际的请求。这样可以减少跨域请求的复杂性和延迟。
对于简单请求

CORS的策略是请求时在请求头中增加一个Origin字段,服务器收到请求后,根据该字段判断是否允许该请求访问。

1.如果允许,则在 HTTP 头信息中添加 Access-Control-Allow-Origin 字段,并返回正确的结果 ;

2.如果不 允许,则不在 HTTP 头信息中添加 Access-Control-Allow-Origin 字段 。

2.非简单请求

对于非简单请求的跨源请求,浏览器会在真实请求发出前,增加一次OPTION请求,称为预检请求(preflight request)。预检请求将真实请求的信息,包括请求方法、自定义头字段、源信息添加到 HTTP 头信息字段中,询问服务器是否允许这样的操作。

例如一个DELETE请求:

java 复制代码
OPTIONS /test HTTP/1.1
Origin: http://www.examples.com
Access-Control-Request-Method: DELETE
Access-Control-Request-Headers: X-Custom-Header
Host: www.examples.com

与 CORS 相关的字段有:

java 复制代码
请求使用的 HTTP 方法 Access-Control-Request-Method ;
请求中包含的自定义头字段 Access-Control-Request-Headers 。
服务器收到请求时,需要分别对 Origin、Access-Control-Request-Method、Access-Control-Request-Headers 进行验证,验证通过后,会在返回 HTTP头信息中添加 :

Access-Control-Allow-Origin: http://www.examples.com
Access-Control-Allow-Methods: GET, POST, PUT, DELETE
Access-Control-Allow-Headers: X-Custom-Header
Access-Control-Allow-Credentials: true
Access-Control-Max-Age: 1728000
他们的含义分别是:

Access-Control-Allow-Methods: 真实请求允许的方法
Access-Control-Allow-Headers: 服务器允许使用的字段
Access-Control-Allow-Credentials: 是否允许用户发送、处理 cookie
Access-Control-Max-Age: 预检请求的有效期,单位为秒。有效期内,不会重复发送预检请求
当预检请求通过后,浏览器会发送真实请求到服务器。这就实现了跨源请求。

总之:跨域请求会经历的几个步骤也就这几步

1.访问另一个域的资源。

2.有可能会发起一次预检请求(非简单请求,或超过了 Max-Age)。

3.发起实际请求。

springboot项目中使用springSecruity导致跨域请求@CrossOrigin请求失效解决方法

第一步

想访问的controller类该加上@CrossOrigin还加上,不要删除

第二步

配置springSecruity配置类,添加跨域配置

下面代码中通过调用http.cors().and().csrf().disable()方法来启用跨域配置并禁用CSRF保护。

java 复制代码
package com.example.sec_demo1.config;

/**
 * @ClassName Sccc
 * @Description TODO
 * @Author zyhh
 * @date 2024/2/29 14:27
 * @version: 1.0
 */

import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.web.cors.CorsUtils;

/**
 * SpringSecurity配置类
 */
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true)
public class SpringSecurityConfig extends WebSecurityConfigurerAdapter {
    /**
     * 授权
     *
     * @param http
     * @throws Exception
     */
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        // 开启跨域访问
        http.cors(); //.disable();
        // 开启模拟请求,比如API POST测试工具的测试,不开启时,API POST为报403错误
        http.csrf().disable();

        // iframe 跳转错误处理 Refused to display 'url' in a frame because it set 'X-Frame-Options' to 'deny'
        http.headers().frameOptions().disable();
        // 当出现跨域的OPTIONS请求时,发现被拦截,加入下面设置可实现对OPTIONS请求的放行。
        http.authorizeRequests().
                requestMatchers(CorsUtils::isPreFlightRequest).
                permitAll();
    }
}

第三步

配置一个CorsConfigurationSource的Bean来定义跨域配置。

通过CorsConfigurationSource的Bean定义了允许的来源、方法和头部,并将其应用到所有路径上。

java 复制代码
@Configuration
public class CorsConfig {

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

=============== over ===================================

再补充一点哈哈

springboot 中的跨域方法

有三种

1.针对单个 API的

2.针对整个应用的

3.在一些情况下是等效的,而在另一些情况下却又出现不同
针对单个API的

其实就是使用@CrossOrigin。可以加类上,也可以加单个方法上。
针对整个应用的

实现 WebMvcConfigurerz中的addCorsMappings 方法

java 复制代码
/**
 * SpringMVC 跨域配置
 */
@Configuration
public class MvcConfig implements WebMvcConfigurer {

    @Bean
    public CorsFilter corsFilter() {
        final UrlBasedCorsConfigurationSource urlBasedCorsConfigurationSource = new UrlBasedCorsConfigurationSource();
        final CorsConfiguration corsConfiguration = new CorsConfiguration();
        corsConfiguration.setAllowCredentials(true); /*是否允许请求带有验证信息*/
        corsConfiguration.addAllowedOrigin("*");/*允许访问的客户端域名*/
        corsConfiguration.addAllowedHeader("*");/*允许服务端访问的客户端请求头*/
        corsConfiguration.addAllowedMethod("*"); /*允许访问的方法名,GET POST等*/
        corsConfiguration.addExposedHeader("token");/*暴露哪些头部信息 不能用*因为跨域访问默认不能获取全部头部信息*/
        corsConfiguration.addExposedHeader("TOKEN");
        corsConfiguration.addExposedHeader("Authorization");
        urlBasedCorsConfigurationSource.registerCorsConfiguration("/**", corsConfiguration);
        return new CorsFilter(urlBasedCorsConfigurationSource);
    }
}

在一些情况下是等效的,而在另一些情况下却又出现不同

注入 CorsFilter

注入 CorsFilter 不止这一种方式,我们还可以通过注入一个 FilterRegistrationBean 来实现,这里就不给例子了。

java 复制代码
@WebFilter("/*")
public class CORSFilter implements Filter {

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain chain) throws IOException, ServletException, ServletException, IOException {
        HttpServletRequest request = (HttpServletRequest) servletRequest;
        HttpServletResponse resp = (HttpServletResponse) servletResponse;

        // 告诉浏览器允许所有的域访问
        // 注意 * 不能满足带有cookie的访问,Origin 必须是全匹配
        // resp.addHeader("Access-Control-Allow-Origin", "*");
        // 解决办法通过获取Origin请求头来动态设置
        String origin = request.getHeader("Origin");
        if (StringUtils.hasText(origin)) {
            resp.addHeader("Access-Control-Allow-Origin", origin);
        }
        // 允许带有cookie访问
        resp.addHeader("Access-Control-Allow-Credentials", "true");

        // 告诉浏览器允许跨域访问的方法
        resp.addHeader("Access-Control-Allow-Methods", "*");

        // 告诉浏览器允许带有Content-Type,header1,header2头的请求访问
        // resp.addHeader("Access-Control-Allow-Headers", "Content-Type,header1,header2");
        // 设置支持所有的自定义请求头
        String headers = request.getHeader("Access-Control-Request-Headers");
        if (StringUtils.hasText(headers)) {
            resp.addHeader("Access-Control-Allow-Headers", headers);
        }

        // 告诉浏览器缓存OPTIONS预检请求1小时,避免非简单请求每次发送预检请求,提升性能
        resp.addHeader("Access-Control-Max-Age", "3600");

        chain.doFilter(request, resp);
    }
}

以上是springboot才需要的配置,如果是springboot+springSecruity。这些是没办法使用的。得使用

CorsConfigurationSource配置类和 继承WebSecurityConfigurerAdapter类并实现configure方法。

相关推荐
用户21411832636024 分钟前
dify案例分享-零代码搞定 DIFY 插件开发:小白也能上手的文生图插件实战
后端
计算机程序员小杨14 分钟前
计算机专业的你懂的:大数据毕设就选贵州茅台股票分析系统准没错|计算机毕业设计|数据可视化|数据分析
java·大数据
y1y1z18 分钟前
EasyExcel篇
java·excel
DokiDoki之父38 分钟前
多线程—飞机大战排行榜功能(2.0版本)
android·java·开发语言
高山上有一只小老虎44 分钟前
走方格的方案数
java·算法
whatever who cares44 分钟前
Java 中表示数据集的常用集合类
java·开发语言
石小石Orz1 小时前
效率提升一倍!谈谈我的高效开发工具链
前端·后端·trae
JavaArchJourney1 小时前
TreeMap 源码分析
java
孟永峰_Java1 小时前
凌晨线上崩盘:NoClassDefFoundError血案纪实!日志里这行「小字」才是救世主
后端·代码规范
whitepure1 小时前
万字详解Java中的IO及序列化
java·后端