SpringBoot 解决跨域问题


一个简洁的博客网站:http://lss-coding.top,欢迎大家来访
学习娱乐导航页:http://miss123.top/


1. 什么是跨域?

当一个请求 URL 的协议、域名、端口号三者之间任意一个与当前页面 URL 不同即为跨域。

当前页面 URL被请求页面 URL是否跨域原因
http://www.myweb.com/http://www.myweb.com/index.html同源(协议、域名、端口号相同)
http://www.myweb.com/https://www.myweb.com/index.html协议不同(http/https)
http://www.myweb.com/http://www.taobao.com/主域名不同(myweb/taobao)
http://www.myweb.com/http://blog.taobao.com/子域名不同(www/blog)
http://www.myweb.com:8001/http://www.myweb.com:8002/端口号不同(8001/8002)

2. 跨域产生的原因?

浏览器的同源策略限制

同源策略:URL 是由协议、域名、端口号和路径组成的,如果两个 URL 的协议、域名和端口号相同,则表示这两个 URL 是同源的。浏览器的同源策略,从一个域上加载的脚本不允许访问另外一个域的文档属性,是浏览器上为安全性考虑实施的非常重要的安全策略。

同源策略(Same Origin Policy)是一种约定,是浏览器核心也是最基本的安全功能,它会阻止一个域的 js 脚本和另外一个域的内容进行交互,如果缺少了同源策略,浏览器很容易受到 XSS、CSRF 等攻击,浏览器的正常功能都会受到影响。所谓同源(即在同一个域),就是两个页面具有相同的协议(protocol)、主机(host)和端口号(port)

简答说 A 应用只能访问 A 应用后台传来的数据,B应用只能访问 B 应用后台传来的数据,如果 A 应用用 ajax 获取数据时的 URL 地址中 协议、端口、域名 其中有一个和 B 应用对应的话(即请求 URL 与 A 应用的 URL 不同),则是 A 应用跨域了想获取 B 应用的数据,是不允许的。

例如:在一个恶意网站的页面通过 iframe 嵌入了一个银行的登录页面(恶意网站和登录页面是不同源的),如果没有同源限制,恶意网页上的 javascript 脚本就可以在用户登录银行账号的时候获取用户名和密码。

非同源限制:

浏览器为了安全,限制了一些请求无法访问非同源 URL

  • 无法读取非同源网页的 Cookie、LoacalStorage 和 IndexedDB
  • 无法接触非同源网页的 DOM
  • 无法向非同源地址发送 ajax 请求

3. SpringBoot 解决跨域

以下三种方法都可以解决跨域的问题,三种方法不能同时使用,否则会出现问题,所以只能选定一种方法来解决跨域问题。

其实无论哪种方案,最终目的都是修改响应头,向响应头中添加浏览器所要求的数据,进而实现跨域。

3.1 使用注解 @CrossOrigin(局部跨域)
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface CrossOrigin {

   /** @deprecated as of Spring 5.0, in favor of {@link CorsConfiguration#applyPermitDefaultValues} */
   @Deprecated	// 不推荐使用
   String[] DEFAULT_ORIGINS = {"*"};

   /** @deprecated as of Spring 5.0, in favor of {@link CorsConfiguration#applyPermitDefaultValues} */
   @Deprecated // 不推荐使用
   String[] DEFAULT_ALLOWED_HEADERS = {"*"};

   /** @deprecated as of Spring 5.0, in favor of {@link CorsConfiguration#applyPermitDefaultValues} */
   @Deprecated // 不推荐使用
   boolean DEFAULT_ALLOW_CREDENTIALS = false;

   /** @deprecated as of Spring 5.0, in favor of {@link CorsConfiguration#applyPermitDefaultValues} */
   @Deprecated // 不推荐使用
   long DEFAULT_MAX_AGE = 1800;


   /**
    * Alias for {@link #origins}.
    */
    // 这里 value 和下面的 origins 是一样的
    // 允许来源域名的列表,例如 'www.taobao.com',匹配的域名是跨域预请求 Response 头中的 'Access-Control-Allow_origin'
    // 字段值,不设置确切值时默认支持所有域名跨域访问。
   @AliasFor("origins")
   String[] value() default {};

   /**
    * The list of allowed origins that be specific origins, e.g.
    * {@code "https://domain1.com"}, or {@code "*"} for all origins.
    * <p>A matched origin is listed in the {@code Access-Control-Allow-Origin}
    * response header of preflight actual CORS requests.
    * <p>By default all origins are allowed.
    * <p><strong>Note:</strong> CORS checks use values from "Forwarded"
    * (<a href="https://tools.ietf.org/html/rfc7239">RFC 7239</a>),
    * "X-Forwarded-Host", "X-Forwarded-Port", and "X-Forwarded-Proto" headers,
    * if present, in order to reflect the client-originated address.
    * Consider using the {@code ForwardedHeaderFilter} in order to choose from a
    * central place whether to extract and use, or to discard such headers.
    * See the Spring Framework reference for more on this filter.
    * @see #value
    */
   @AliasFor("value")
   String[] origins() default {};

   /**
    * The list of request headers that are permitted in actual requests,
    * possibly {@code "*"}  to allow all headers.
    * <p>Allowed headers are listed in the {@code Access-Control-Allow-Headers}
    * response header of preflight requests.
    * <p>A header name is not required to be listed if it is one of:
    * {@code Cache-Control}, {@code Content-Language}, {@code Expires},
    * {@code Last-Modified}, or {@code Pragma} as per the CORS spec.
    * <p>By default all requested headers are allowed.
    */
    // 跨域请求中允许的请求头中的字段类型,该值对应跨域预请求 Response 头中的 'Access-Control-Allow-Headers' 字段值
    // 不设置确切值默认支持所有的 header 字段(Cache-Controller、Content-Language、Content-Type、Expires、Last-Modified、Pragma)跨域访问
   String[] allowedHeaders() default {};

   /**
    * The List of response headers that the user-agent will allow the client
    * to access on an actual response, other than "simple" headers, i.e.
    * {@code Cache-Control}, {@code Content-Language}, {@code Content-Type},
    * {@code Expires}, {@code Last-Modified}, or {@code Pragma},
    * <p>Exposed headers are listed in the {@code Access-Control-Expose-Headers}
    * response header of actual CORS requests.
    * <p>By default no headers are listed as exposed.
    */
    // 跨域请求头中允许携带的除 Cache-Controller、Content-Language、Content-Type、Expires、Last-Modified、
    // Pragma 这六个基本字段之外的其他字段信息、对应的跨域请求 Response 头中的 'Access-control-Expose-Headers'字段值
   String[] exposedHeaders() default {};

   /**
    * The list of supported HTTP request methods.
    * <p>By default the supported methods are the same as the ones to which a
    * controller method is mapped.
    */
    // 跨域 HTTP 请求中支持的 HTTP 请求类型(GET、POST...),不指定确切值时默认与 Controller 方法中的 methods 字段保持一致
   RequestMethod[] methods() default {};

   /**
    * Whether the browser should send credentials, such as cookies along with
    * cross domain requests, to the annotated endpoint. The configured value is
    * set on the {@code Access-Control-Allow-Credentials} response header of
    * preflight requests.
    * <p><strong>NOTE:</strong> Be aware that this option establishes a high
    * level of trust with the configured domains and also increases the surface
    * attack of the web application by exposing sensitive user-specific
    * information such as cookies and CSRF tokens.
    * <p>By default this is not set in which case the
    * {@code Access-Control-Allow-Credentials} header is also not set and
    * credentials are therefore not allowed.
    */
    // 该值对应的是跨域请求 Response 头中的 'Access-Control-Allow-Credentials' 字段值。
    // 浏览器是否将本域名下的 cookie 信息携带至跨域服务器中。默认携带至跨域服务器中,但实现 cookie
    // 共享还需要前端在 ajax 请求中打开 withCredentials 属性
   String allowCredentials() default "";

   /**
    * The maximum age (in seconds) of the cache duration for preflight responses.
    * <p>This property controls the value of the {@code Access-Control-Max-Age}
    * response header of preflight requests.
    * <p>Setting this to a reasonable value can reduce the number of preflight
    * request/response interactions required by the browser.
    * A negative value means <em>undefined</em>.
    * <p>By default this is set to {@code 1800} seconds (30 minutes).
    */
    // 该值对应的是跨域请求 Response 头中的 'Access-Control-Max-Age' 字段值,表示预检请求响应的缓存持续的最大时间,
    // 目的是减少浏览器预检请求/响应交互的数量。默认值 1800s。设置了该值后,浏览器将在设置值的时间段内对该跨域请求不再发起预请求
   long maxAge() default -1;

}
  1. 在控制器(类上)使用注解解决跨域,表示该类下的所有方法都允许跨域
@Controller
@CrossOrigin(origins = "*", methods = {RequestMethod.GET,RequestMethod.POST})
public class SystemController extends BaseController {

    @GetMapping("/test")
    @ResponseBody
    public String test() {
        return "test @CrossOrigin";
    }
}
  1. 在方法上使用注解解决跨域,表示只有该方法允许跨域
@Controller
public class SystemController extends BaseController {

    // 设置只能某些地址访问
    @CrossOrigin(origins = "http://localhost:9999")
    @GetMapping("/test")
    @ResponseBody
    public String test() {
        return "test @CrossOrigin";
    }
}
3.2 配置 CorsFilter(全局跨域)
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;

@Configuration
public class WebGlobalConfig {
    @Bean
    public CorsFilter corsFilter() {
        // 1. 创建 CorsConfiguration 对象后添加配置
        CorsConfiguration configuration = new CorsConfiguration();
        // 设置放行那些域
        configuration.addAllowedOrigin("*");
        // 放行那些原始请求头部信息
        configuration.addAllowedHeader("*");
        // 暴露那些头部信息
        configuration.addExposedHeader("*");
        // 放行那些请求方式
        configuration.addAllowedMethod("GET");  // get
        configuration.addAllowedMethod("POST");  // post
        configuration.addAllowedMethod("PUT");  // put
        configuration.addAllowedMethod("DELETE");  // delete
        // configuration.addAllowedMethod("*"); // 放行全部请求
        // 是否发送 Cookie
        configuration.setAllowCredentials(true);
        // 2. 添加映射路径
        UrlBasedCorsConfigurationSource source =
                new UrlBasedCorsConfigurationSource();
        source.registerCorsConfiguration("/**", configuration);
        // 3. 返回 CorsFilter
        return new CorsFilter(source);
    }
}
3.3 重写 WebMvcConfigurer 的 addCorsMappings 方法(全局跨域)
@Configuration
public class MyWebMvcConfigurer implements WebMvcConfigurer {

    @Override
    public void addCorsMappings(CorsRegistry registry) {
        // 添加映射路径
        registry.addMapping("/**")
                // 是否发送 Cookie
                .allowCredentials(true)
                // 设置放行那些原始域
                .allowedOrigins("*")
                // 放行那些请求方式
                .allowedMethods(new String[]{"GET", "POST", "PUT", "DELETE"})
                // .allowedMethods("*")     // 放行全部
                // 放行那些原始请求头部信息
                .allowedHeaders("*")
                // 暴露那些原始请求头部信息
                .exposedHeaders("*");
    }
}

**学习参考地址:**https://www.cnblogs.com/antLaddie/p/14751540.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值