Support Cors cross domain requests using SpringCloudApiGateway

  • 2021-10-27 07:43:15
  • OfStack

Problem background

The company's project needs to separate the front and back ends, vue + java, so it needs to support Cors cross-domain requests. Recently, zuul has been upgraded. If zuul is 1.0, api gateway is the gateway of 2.0, which supports ws, etc. Based on NIO, it is still powerful in all aspects.

Solutions

Just create a new Configuration class


import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.cloud.gateway.discovery.DiscoveryClientRouteDefinitionLocator;
import org.springframework.cloud.gateway.route.RouteDefinitionLocator;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.HttpStatus;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.web.cors.reactive.CorsUtils;
import org.springframework.web.server.ServerWebExchange;
import org.springframework.web.server.WebFilter;
import org.springframework.web.server.WebFilterChain;
import reactor.core.publisher.Mono;
/**
 * SpringApiGateway Cors
 */
@Configuration
public class RouteConfiguration {
    // Here is the supported request header, if there is a custom header Please add the field by yourself (I don't know why I can't use it * ) 
    private static final String ALLOWED_HEADERS = "x-requested-with, authorization, Content-Type, Authorization, credential, X-XSRF-TOKEN,token,username,client";
    private static final String ALLOWED_METHODS = "*";
    private static final String ALLOWED_ORIGIN = "*";
    private static final String ALLOWED_Expose = "x-requested-with, authorization, Content-Type, Authorization, credential, X-XSRF-TOKEN,token,username,client";
    private static final String MAX_AGE = "18000L";
    @Bean
    public WebFilter corsFilter() {
        return (ServerWebExchange ctx, WebFilterChain chain) -> {
            ServerHttpRequest request = ctx.getRequest();
            if (CorsUtils.isCorsRequest(request)) {
                ServerHttpResponse response = ctx.getResponse();
                HttpHeaders headers = response.getHeaders();
                headers.add("Access-Control-Allow-Origin", ALLOWED_ORIGIN);
                headers.add("Access-Control-Allow-Methods", ALLOWED_METHODS);
                headers.add("Access-Control-Max-Age", MAX_AGE);
                headers.add("Access-Control-Allow-Headers", ALLOWED_HEADERS);
                headers.add("Access-Control-Expose-Headers", ALLOWED_Expose);
                headers.add("Access-Control-Allow-Credentials", "true");
                if (request.getMethod() == HttpMethod.OPTIONS) {
                    response.setStatusCode(HttpStatus.OK);
                    return Mono.empty();
                }
            }
            return chain.filter(ctx);
        };
    }
    /**
    *
    * If a registry is used, such as: Eureka ), the following configuration needs to be added for control 
    */
    @Bean
    public RouteDefinitionLocator discoveryClientRouteDefinitionLocator(DiscoveryClient discoveryClient) {
        return new DiscoveryClientRouteDefinitionLocator(discoveryClient);
    }
}

application. yml configuration

The official document mentioned that there is another way to configure it through yml.


spring:
  cloud:
    gateway:
      globalcors:
        corsConfigurations:
          '[/**]':
            allowedOrigins: "https://blog.csdn.net/moshowgame"
            allowedMethods:
            - GET

Cross-domain solution (CORS)

1. What is cross-domain?

The cross-domain problem is due to the browser's "homology policy" restriction. Homologous policy (Sameoriginpolicy) is a convention, which is the core and basic security function of browser. If there is no homologous policy, the normal function of browser may be affected.

It can be said that Web is built on the basis of homologous policy, and browser is only one implementation of homologous policy. The homology policy prevents the javascript script of one domain from interacting with the content of the other domain.

Homologous (that is, in the same domain) means that two pages have the same protocol (protocol), host (host) and port number (port)

Because we are now adopting a micro-service architecture with the separation of front and back ends, there must be cross-domain problems between front and back ends. CORS can be used to solve cross-domain problems.

2. Introduction to CORS

CORS is an W3C standard, and its full name is "Cross-domain Resource Sharing" (Cross-origin resource sharing).

CORS requires both browser and server support. But at present, browsers basically support it, so we can communicate across sources as long as we ensure that the server-side server implements CORS interface.

The browser divides CORS requests into two categories: simple requests (simple request) and non-simple requests (not-so-simple request).

3. Specific solutions

To solve the cross-domain problem, it is to add header information to the response on the server side

Name Required Comments
Access-Control-Allow-Origin 必填 允许请求的域
Access-Control-Allow-Methods 必填 允许请求的方法
Access-Control-Allow-Headers 可选 预检请求后,告知发送请求需要有的头部
Access-Control-Allow-Credentials 可选 表示是否允许发送cookie,默认false;
Access-Control-Max-Age 可选 本次预检的有效期,单位:秒;
3.1 Solving in Spring Boot

The @ CrossOrigin annotation is provided in spring boot to solve cross-domain problems.

Usage scenario requirements: jdk1.8 +, Spring4.2 +

Just add @ CrossOrigin to the controller we need


@RestController
// Implement cross-domain annotations 
//origin="*" Represents that all domain names are accessible 
//maxAge The maximum age of cache duration of pre-flight response is simply Cookie Validity period of   The unit is seconds if maxAge Is a negative number , It stands for temporary Cookie, Will not be persisted ,Cookie Information is stored in browser memory , Browser closed Cookie Disappears 
@CrossOrigin(origins = "*",maxAge = 3600)
@RequestMapping("/album")
public class AlbumController {}
3.2 Solving in spring Cloud

Just add the configuration in the spring Cloud Gateway service


spring:
  application:
    name: system-gateway
  cloud:
    gateway:
      globalcors:
        cors-configurations:
          '[/**]': #  Matching all requests 
            allowedOrigins: "*" # Cross-domain processing   Allow all domains 
            allowedMethods: #  Supported methods 
            - GET
            - POST
            - PUT
            - DELETE

Of course, you can also use the interceptor of Gateway to manually add the corresponding header information


default-filters:
      - AddResponseHeader=Access-Control-Allow-Credentials,true
      - AddResponseHeader=Access-Control-Allow-Headers,access-control-allow-origin
      - AddResponseHeader=Access-Control-Allow-Methods,GET
      - AddResponseHeader=Access-Control-Allow-Origin,*
      - AddResponseHeader=Access-Control-Allow-Age,3600
3.3 Resolving in Nginx

location /example {
   if ($request_method = 'OPTIONS') {
       add_header Access-Control-Allow-Origin *;
       add_header Access-Control-Max-Age 1728000;
       add_header Access-Control-Allow-Methods GET,POST,OPTIONS;
       add_header Access-Control-Allow-Headers  'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range';
       add_header Content-Type' 'text/plain; charset=utf-8';
       add_header Content-Length 0 ;
       return 204;
    }
 
+   if ($http_origin ~* (https?://(.+\.)?(example\.com$))) {
+     add_header  Access-Control-Allow-Origin $http_origin;
+     add_header  Access-Control-Allow-Credentials true;
+     add_header  Access-Control-Allow-Methods GET,POST,OPTIONS;
+     add_header  Access-Control-Expose-Headers Content-Length,Content-Range;
+   }
 
    proxy_redirect off;
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_pass http://127.0.0.1:8080/;
   }

Explanation:

if ($request_method = 'OPTIONS') {...} When the request method is OPTIONS:

Adding allows source Access-Control-Allow-Origin to be * (can be changed according to business needs) Add the cache duration Access-Control-Max-Age so that no more OPTIONS requests are needed when the next request is made Add allowed methods, allowed headers Add 1 content length 0, type text/plain; charset=utf-8, returning the header with a status code of 204

if ($http_origin ~ * (https? ://(. +\.)? (example\. com $)) {...}, when origin is a legal domain name (legal domain name authentication can be adjusted or removed according to business):

Adding allows source Access-Control-Allow-Origin to be $http_origin (can be changed according to business needs) Add Access-Control-Allow-Credentials to allow authentication as true, and allow receiving client Cookie (which can be changed according to business needs. Note, however, that when set to true, Access-Control-Allow-Origin is not allowed to be set to *) Add allowed methods, expose headers

At this point, the correct response of cross-domain request is completed.


Related articles: