spring如何解决跨域访问的五种方案

Spring Cloud配置跨域访问的五种方案

(转自并添加了自己的方案:https://segmentfault.com/a/1190000017188296)

在使用SpringCloud实现微服务时,经常会碰到前端页面访问多个二级域名的情况,跨域是首先要解决的问题。
解决这个问题,可以从两方面入手,一种方案是在微服务各自的业务模块中实现,即在SpringBoot层实现,另外一种方案就是在Gateway层实现。

首先讲一下在SpringBoot层实现的三种方案。

解决方案一:在Controller上添加@CrossOrigin注解

这种方式适合只有一两个rest接口需要跨域或者没有网关的情况下,这种处理方式就非常简单,适合在原来基代码基础上修改,影响比较小。

    @CrossOrigin // 注解方式
    @RestController
    public class HandlerScanController {
        @CrossOrigin(allowCredentials="true", 
                allowedHeaders="*", 
                methods= {
                    RequestMethod.GET,
                    RequestMethod.POST, 
                    RequestMethod.DELETE,                                        
                    RequestMethod.OPTIONS,
                    RequestMethod.HEAD,
                    RequestMethod.PUT,
                    RequestMethod.PATCH},
                origins="*")

        @PostMapping("/confirm")
        public Response handler(@RequestBody Request json){
            return null;

        }
    }

解决方案二:增加WebMvcConfigurer全局配置
如果有大量的rest接口的时候,显然第一种方案已经不适合了,工作量大,也容易出错,那就通过全局配置的方式,允许SpringBoot端所有的rest接口都支持跨域访问,这个时候就需要考虑安全性的问题。
代码如下:

    @Configuration
    public class MyConfiguration {
        @Bean
        public WebMvcConfigurer corsConfigurer() {
            return new WebMvcConfigurerAdapter() {
                @Override
                public void addCorsMappings(CorsRegistry registry) {
                    registry.addMapping("/**")
                            .allowCredentials(true)
                            .allowedMethods("GET");
                }
            };
        }
    }

解决方案三:结合Filter使用

这种方案的使用场景跟第二种方案类似,只不过换成使用Filter的方式实现。
在spring boot的主类中,增加一个CorsFilter

 /**  

  * attention:简单跨域就是GET,HEAD和POST请求,但是POST请求  的"Content-Type"只能是application/x-www-form-urlencoded, multipart/form-data 或 text/plain 

 * 反之,就是非简单跨域,此跨域有一个预检机制,说直白点,就是会发两次请求,一次OPTIONS请求,一次真正的请求

  */

     @Bean

   public CorsFilter corsFilter() {

        final UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();

       final CorsConfiguration config = new CorsConfiguration();

        config.setAllowCredentials(true); // 允许cookies跨域

        config.addAllowedOrigin("*");// #允许向该服务器提交请求的URI,*表示全部允许,在SpringMVC中,如果设成*,会自动转成当前请求头中的Origin

        config.addAllowedHeader("*");// #允许访问的头信息,*表示全部

        config.setMaxAge(18000L);// 预检请求的缓存时间(秒),即在这个时间段里,对于相同的跨域请求不会再预检了

        config.addAllowedMethod("OPTIONS");// 允许提交请求的方法,*表示全部允许

        config.addAllowedMethod("HEAD");

        config.addAllowedMethod("GET");// 允许Get的请求方法

        config.addAllowedMethod("PUT");

        config.addAllowedMethod("POST"); 

        config.addAllowedMethod("DELETE");

        config.addAllowedMethod("PATCH");

        source.registerCorsConfiguration("/**", config);

        return new CorsFilter(source);

}

以上这种方案如果微服务多的话,需要在每个服务的主类上都加上这么段代码,增加了维护量。
以上三种方案都是在SpringBoot的基础上实现的解决方案,在模块较多或者接口较多的情况下不易维护。
既然SpringCloud自带Gateway,下面就讲讲使用Gateway的跨域解决方案。

解决方案四,在Gateway端增加CorsFilter拦截器
这种方案跟方案三有些类似,只不过是放到了Gateway端,对于有多个微服务模块的情况下,就大大减少了SpringBoot模块端的代码量,让各个模块更集中精力做业务逻辑实现。
这个方案只需要在Gateway里添加Filter代码类即可。

private static final String ALL = "*";

private static final String MAX_AGE = "18000L";

@Override

public Mono<Void> filter(ServerWebExchange ctx, WebFilterChain chain) {

    ServerHttpRequest request = ctx.getRequest();

    String path=request.getPath().value();

    ServerHttpResponse response = ctx.getResponse();

    if("/favicon.ico".equals(path)) {

        response.setStatusCode(HttpStatus.OK);

        return Mono.empty();

    }

    

    if (!CorsUtils.isCorsRequest(request)) {

        return chain.filter(ctx);

    }

    HttpHeaders requestHeaders = request.getHeaders();

    

    HttpMethod requestMethod = requestHeaders.getAccessControlRequestMethod();

    HttpHeaders headers = response.getHeaders();

    headers.add(HttpHeaders.ACCESS_CONTROL_ALLOW_ORIGIN, requestHeaders.getOrigin());

    headers.addAll(HttpHeaders.ACCESS_CONTROL_ALLOW_HEADERS, requestHeaders.getAccessControlRequestHeaders());

    if (requestMethod != null) {

        headers.add(HttpHeaders.ACCESS_CONTROL_ALLOW_METHODS, requestMethod.name());

    }

    headers.add(HttpHeaders.ACCESS_CONTROL_ALLOW_CREDENTIALS, "true");

    headers.add(HttpHeaders.ACCESS_CONTROL_EXPOSE_HEADERS, ALL);

    headers.add(HttpHeaders.ACCESS_CONTROL_MAX_AGE, MAX_AGE);

    if (request.getMethod() == HttpMethod.OPTIONS) {

        response.setStatusCode(HttpStatus.OK);

        return Mono.empty();

    }

    

    

    return chain.filter(ctx);

}



或者

在网关中定义“MyCorsConfiguration”类,该类用来做过滤,允许所有的请求跨域。

@Configuration
public class MyCorsConfiguration {

    @Bean
    public CorsWebFilter corsWebFilter(){
        UrlBasedCorsConfigurationSource source=new UrlBasedCorsConfigurationSource();
        CorsConfiguration corsConfiguration = new CorsConfiguration();
        corsConfiguration.addAllowedHeader("*");
        corsConfiguration.addAllowedMethod("*");
        corsConfiguration.addAllowedOrigin("*");
        corsConfiguration.setAllowCredentials(true);
        
        source.registerCorsConfiguration("/**",corsConfiguration);
        return new CorsWebFilter(source);
    }
}

解决方案五,修改Gateway配置文件(不好使,大概率不起效)
在仔细阅读过Gateway的文档你就会发现,原来CorsFilter早已经在Gateway里了,不需要自己写代码实现,而且更灵活,修改配置文件即可,结合配置中心使用,可以实现动态修改。
application.yml.

spring:
  cloud:
    gateway:
      globalcors:
        cors-configurations:
          '[/**]': 
            # 允许携带认证信息
            # 允许跨域的源(网站域名/ip),设置*为全部
            # 允许跨域请求里的head字段,设置*为全部
            # 允许跨域的method, 默认为GET和OPTIONS,设置*为全部
            # 跨域允许的有效期
            allow-credentials: true
            allowed-origins: 
            - "http://localhost:13009"
            - "http://localhost:13010"
            allowed-headers: "*"
            allowed-methods: 
            - OPTIONS
            - GET
            - POST
            max-age: 3600
            # 允许response的head信息
            # 默认仅允许如下6个:
            #     Cache-Control
            #     Content-Language
            #     Content-Type
            #     Expires
            #     Last-Modified
            #     Pragma

以上五种跨域方案。

  • 1
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Spring Security 并不直接解决跨域问题,而是通过集成 Spring MVC 提供的跨域解决方案来处理。 在 Spring MVC 中,可以通过添加 `@CrossOrigin` 注解来实现跨域访问。在 Spring Security 中,可以通过配置 `WebSecurityConfigurerAdapter` 来添加 `CorsConfigurationSource`,从而实现跨域访问。 具体实现方法如下: 1. 在配置类中添加 `CorsConfigurationSource`: ``` @Configuration @EnableWebSecurity public class WebSecurityConfig extends WebSecurityConfigurerAdapter { @Bean public CorsConfigurationSource corsConfigurationSource() { CorsConfiguration configuration = new CorsConfiguration(); configuration.setAllowedOrigins(Arrays.asList("*")); configuration.setAllowedMethods(Arrays.asList("*")); configuration.setAllowedHeaders(Arrays.asList("*")); UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(); source.registerCorsConfiguration("/**", configuration); return source; } // ... } ``` 2. 将 `CorsFilter` 添加到 Spring Security 过滤器链中: ``` @Configuration @EnableWebSecurity public class WebSecurityConfig extends WebSecurityConfigurerAdapter { // ... @Override protected void configure(HttpSecurity http) throws Exception { http // ... .cors() .and() // ... } @Bean public CorsFilter corsFilter() { UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(); CorsConfiguration config = new CorsConfiguration(); config.setAllowCredentials(true); config.addAllowedOrigin("*"); config.addAllowedHeader("*"); config.addAllowedMethod("*"); source.registerCorsConfiguration("/**", config); return new CorsFilter(source); } } ``` 这样就可以通过 Spring Security 实现跨域访问了。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值