SpringBoot configures CORS to handle cross-domain problems of front – and back-end separation

1. Why cross-domain problems?

Cross-domain doesn’t always have cross-domain problems.

The cross-domain problem is a security limitation imposed by browsers on Ajax requests: Ajax requests from a page can only be sent in the same path as the current page domain name, which effectively prevents cross-site attacks.

Therefore: Cross-domain issues are a limitation against Ajax.

2. Solutions to cross-domain problems

Currently, there are three commonly used cross-domain solutions:

  • Jsonp

    The earliest solutions, using script tags, can be implemented across domains.

    Limitations:

    • Service support is required
    • Only GET requests can be made
  • Nginx reverse proxy

    The idea is: use Nginx to cross-domain reverse proxy for non-cross-domain, support a variety of requests

    Disadvantages: Additional configuration in Nginx, semantic ambiguity

  • CORS

    Standardized cross-domain request solution, safe and reliable.

    Advantage:

    • You can customize rules to control whether to allow cross-domains on the server
    • Supports various request modes

    Disadvantages:

    • Additional requests are generated

To sum up the comparison of the above three ways, we adopt the cross-domain scheme of CORS!

3. Cors solution across domains

3.1. What is CORS

CORS is a W3C standard, which stands for cross-origin Resource Sharing.

It allows browsers to issue XMLHttpRequest requests across source servers, overcoming the limitation that AJAX can only be used in the same source.

CORS requires both browser and server support. Currently, all browsers support this function, and Internet Explorer cannot be lower than Internet Explorer 10.

  • Browser side:

    Currently, all browsers support this feature (not under IE10). The entire CORS communication process is completed automatically by the browser without user participation.

  • Server:

    CORS communication is no different from Ajax, so you don’t need to change your business logic. However, the browser will carry some header information in the request, which we need to use to determine whether to allow it to cross domains, and then add some information to the response header. This is usually done through a filter.

3.2. The principle is a bit complicated

Browsers divide Ajax requests into two categories, which handle them slightly differently:

  • A simple request
  • Special request

3.2.1. Simple request

It is a simple request as long as the following two conditions are met:

(1) Request method is one of the following three methods:

  • HEAD
  • GET
  • POST

(2) HTTP headers do not exceed the following fields:

  • Accept
  • Accept-Language
  • Content-Language
  • Last-Event-ID
  • Content-Type: Is limited to three valuesapplication/x-www-form-urlencoded,multipart/form-data,text/plain

When the browser discovers that the originating Ajax request is a simple request, it carries a field in the request header: Origin!

Origin indicates which domain (protocol + domain + port) the current request belongs to, and the service determines whether to allow it to cross domains based on this value.

If the server allows cross-domain, you need to return the following information in the response header:

Access-Control-Allow-Origin: http://manage.leyou.com
Access-Control-Allow-Credentials: true
Content-Type: text/html; charset=utf-8
Copy the code
  • Access-Control-Allow-Origin: Acceptable domain, is a specific domain name or*(representing any domain name)
  • Access-control-allow-credentials: Specifies whether cookies are allowed. By default, CORS does not carry cookies unless this value is true

The cookies:

To manipulate cookies, three conditions need to be met:

  • Need to be carried in the response header of the serviceAccess-Control-Allow-CredentialsAnd fortrue;
  • The browser needs to specify withCredentials to initiate Ajaxtrue;
  • In the response headerAccess-Control-Allow-OriginMust not be*, must be the specified domain name.

3.2.2. Special request

If a simple request does not meet the requirements, the browser considers it as a special request. For example, the request mode is PUT.

Preview the request

Special requests are preceded by an HTTP query request, called a “preflight” request.

The browser asks the server if the domain name of the current web page is on the server’s license list, and what HTTP verb and header fields can be used. The browser issues a formal XMLHttpRequest request only if it receives a positive response; otherwise, an error is reported.

A sample “precheck” request:

OPTIONS /cors HTTP / 1.1
Origin: http://manage.leyou.com
Access-Control-Request-Method: PUT
Access-Control-Request-Headers: X-Custom-Header
Host: api.leyou.com
Accept-Language: en-US
Connection: keep-alive
User-Agent: Mozilla / 5.0...Copy the code

In addition to Origin, there are two more headers than simple requests:

  • Access-control-request-method: The Request Method to be used next, such as PUT
  • Access-control-request-headers: Additional Headers that will be used

Precheck the response to the request

The service receives a precheck request and issues a response if the permission is cross-domain:

HTTP / 1.1 200 OK
Date: Mon, 01 Dec 2008 01:15:39 GMT
Server: Apache / 2.0.61 (Unix)Access-Control-Allow-Origin: http://manage.leyou.com
Access-Control-Allow-Credentials: true
Access-Control-Allow-Methods: GET, POST, PUT
Access-Control-Allow-Headers: X-Custom-Header
Access-Control-Max-Age: 1728000
Content-Type: text/html; charset=utf-8
Content-Encoding: gzip
Content-Length: 0
Keep-Alive: timeout=2, max=100
Connection: Keep-Alive
Content-Type: text/plain
Copy the code

In addition to the access-Control-allow-origin and access-Control-allow-credentials, there are three additional headers:

  • Access-control-allow-methods: Indicates the allowed Access mode
  • Access-control-allow-headers: allowed Headers
  • Access-control-max-age: The validity period of this permission, in seconds, so that ajax requests before they expire do not need to be prechecked again

If the browser gets the above response, it is considered cross-domain, and the subsequent processing is the same as a simple request.

3.3. The implementation is very simple

Although the principle is complicated, as mentioned above:

  • The browser side has browser autocomplete, we don’t have to worry about
  • The server side can be implemented uniformly through interceptors without having to write cross-domain decisions every time.

As a matter of fact, SpringMVC has already written a cross-domain filter for CORS: CorsFilter. The decision logic is already implemented internally, so we can use it directly.

Write a configuration class CorsConfig in your project and register CorsFilter:

/ * * *@Auther: csp1999
 * @Date: 2020/12/08/18:57
 * @Description: Cross-domain configuration */
@Configuration
public class CorsConfig {

    /** * CORS cross-domain configuration **@return* /
    @Bean
    public CorsFilter corsFilter(a) {
        // 1.new a CORS configuration instance
        CorsConfiguration corsConfiguration = new CorsConfiguration();

        // 1) Allow fields, do not write *, otherwise the cookie will not be used
// corsConfiguration.addAllowedOrigin("http://web.csp1999.com");
        // Set of allowed fields
        List<String> orginList = new ArrayList<>();
        orginList.add("http://web.csp1999.com");
        orginList.add("http://api.csp1999.com");
        corsConfiguration.setAllowedOrigins(orginList);

        // 2) Whether to send Cookie information
        corsConfiguration.setAllowCredentials(true);
        // 3) The allowed request mode
        corsConfiguration.addAllowedMethod("OPTIONS");
        corsConfiguration.addAllowedMethod("HEAD");
        corsConfiguration.addAllowedMethod("GET");
        corsConfiguration.addAllowedMethod("PUT");
        corsConfiguration.addAllowedMethod("POST");
        corsConfiguration.addAllowedMethod("DELETE");
        corsConfiguration.addAllowedMethod("PATCH");
        // 4) Allowed headers
        corsConfiguration.addAllowedHeader("*");

        // 2. Add mapping path, we block all requests
        UrlBasedCorsConfigurationSource urlBasedCorsConfigurationSource = new UrlBasedCorsConfigurationSource();
        urlBasedCorsConfigurationSource.registerCorsConfiguration("/ * *", corsConfiguration);

        // 3. Return a new CorsFilter.
        return newCorsFilter(urlBasedCorsConfigurationSource); }}Copy the code