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方法。

相关推荐
2401_cf1 小时前
为什么hadoop不用Java的序列化?
java·hadoop·eclipse
帮帮志2 小时前
idea整合maven环境配置
java·maven·intellij-idea
LuckyTHP2 小时前
java 使用zxing生成条形码(可自定义文字位置、边框样式)
java·开发语言·python
热河暖男2 小时前
【实战解决方案】Spring Boot+Redisson构建高并发Excel导出服务,彻底解决系统阻塞难题
spring boot·后端·excel
无声旅者5 小时前
深度解析 IDEA 集成 Continue 插件:提升开发效率的全流程指南
java·ide·ai·intellij-idea·ai编程·continue·openapi
0吉光片羽05 小时前
【SpringBoot】集成kafka之生产者、消费者、幂等性处理和消息积压
spring boot·kafka·linq
Ryan-Joee5 小时前
Spring Boot三层架构设计模式
java·spring boot
Hygge-star5 小时前
【数据结构】二分查找5.12
java·数据结构·程序人生·算法·学习方法
dkmilk5 小时前
Tomcat发布websocket
java·websocket·tomcat
工一木子6 小时前
【Java项目脚手架系列】第七篇:Spring Boot + Redis项目脚手架
java·spring boot·redis