Spring boot solves cross domain problems

Posted by Paragon on Sun, 26 Dec 2021 06:52:16 +0100

The separation of front and back ends is the general trend, and the cross domain problem is a commonplace. If you can find a large solution by using the title to google or Baidu, why write it again? Don't hurry to look down.

Problem background:

Same Origin Policy, translated as "Same Origin Policy". It is an important security metric for client-side scripts (especially JavaScript). Its purpose is to prevent a document or script from being loaded from multiple different "Origins". It believes that trusted content loaded from any site is unsafe.

When scripts that are doubted by the browser run in the sandbox, they should only be allowed to access resources from the same site, not those from other sites that may be malicious.

Note: having the same Origin means having the same protocol, host address and port. Once one of the three data items is different, the resource will be considered to be obtained from different origins and will not be allowed to access.

CORS is designed to solve SOP problems. Of course, CORS is not the only solution, but other solutions will not be repeated here.

Introduction to CORS:

CORS is a W3C standard, The full name is "cross origin resource sharing". It allows the browser to send XMLHttpRequest requests to cross source (protocol + domain name + port) servers, thus overcoming the restriction that AJAX can only be used in the same source. CORS requires the support of both the browser and the server. Its communication process is completed automatically by the browser without user participation.

For developers, CORS communication is no different from the same source AJAX/Fetch communication, and the code is exactly the same. Once the browser finds that the request is cross source, it will automatically add some additional header information. Sometimes there will be one more additional request, but the user will not feel it. Therefore, the key to realize CORS communication is the server. As long as the server implements the CORS interface, it can communicate across sources.

The browser divides CORS requests into two categories: simple request and not so simple request.

When the browser sends a CORS simple request, it only needs to add an Origin field in the header information.

When the browser sends a CORS non simple request, it will add an OPTIONS query request before formal communication, It is called "preflight" request. The browser first asks the server whether the domain name of the current web page is in the server's license list, and what HTTP verbs and header information fields can be used. Only when you get a positive reply, the browser will send a formal XMLHttpRequest request, otherwise an error will be reported.

Simple requests are HEAD, GET and POST requests, and the HTTP header information does not exceed the following fields: Accept, Accept language, content language, last event ID and content type note: content type: only limited to three values application/x-www-form-urlencoded, multipart / form data and text/plain

On the contrary, it is not a simple request.

In fact, the implementation of CORS is very simple, that is, adding some response headers on the server, which is insensitive and convenient for the front end.

Detailed response header:

  • Access control allow Origin this field is required. Its value is either the specific value of the Origin field at the time of the request, or a *, indicating that the request for any domain name is accepted.

  • Access control allow methods this field is required. Its value is a comma separated concrete string or *, indicating all cross domain request methods supported by the server. Note that all supported methods are returned, not just the one requested by the browser. This is to avoid multiple "pre check" requests.

  • Access control expose headers this field is optional. During CORS request, the getResponseHeader() method of XMLHttpRequest object can only get six basic fields: cache control, content language, content type, Expires, last modified and Pragma. If you want to get other fields, you must specify them in access control expose headers.

  • Access control allow credentials this field is optional. Its value is a Boolean value indicating whether cookies are allowed to be sent By default, cookies do not occur, that is: false. For requests with special requirements for the server, for example, the request method is PUT or DELETE, or the type of content type field is application/json. This value can only be set to true. If the server does not want to send cookies to the browser, DELETE this field.

  • Access control Max age this field is optional. It is used to specify the validity period of this pre inspection request, in seconds. During the validity period, there is no need to issue another pre inspection request.

By the way, if you find that there are two requests each time during development, one OPTIONS and one normal request, please note that each time, you need to configure access control Max age to avoid sending pre check requests every time.

terms of settlement:

The first approach:

import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration
public class CorsConfig implements WebMvcConfigurer {
    @Override
    public void addCorsMappings(CorsRegistry registry) {
        registry.addMapping("/**")
                .allowedOrigins("*")
                .allowedMethods("GET", "HEAD", "POST", "PUT", "DELETE", "OPTIONS")
                .allowCredentials(true)
                .maxAge(3600)
                .allowedHeaders("*");
    }
}

This method is globally configured, and most solutions are available online, but many are based on the old spring version, such as WebMvcConfigurerAdapter in spring 5 0 has been marked as Deprecated. Click the source code to see:

/**
 * An implementation of {@link WebMvcConfigurer} with empty methods allowing
 * subclasses to override only the methods they're interested in.
 *
 * @author Rossen Stoyanchev
 * @since 3.1
 * @deprecated as of 5.0 {@link WebMvcConfigurer} has default methods (made
 * possible by a Java 8 baseline) and can be implemented directly without the
 * need for this adapter
 */
@Deprecated
public abstract class WebMvcConfigurerAdapter implements WebMvcConfigurer {}

For such outdated classes or methods, spring authors will explain the reasons in the comments and tell you which to use for the new ones. This is a very good coding habit. Praise!

Spring 5 supports jdk1.0 as a minimum 8, so the comments clearly indicate that you can directly implement the WebMvcConfigurer interface without using this adapter, because jdk1 8. Default method exists in the support interface.

I won't introduce the basics of Spring Boot. This tutorial is too complete:

https://github.com/javastacks/spring-boot-best-practice

The second approach:

import org.springframework.context.annotation.Configuration;
import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@WebFilter(filterName = "CorsFilter ")
@Configuration
public class CorsFilter implements Filter {
    @Override
    public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
        HttpServletResponse response = (HttpServletResponse) res;
        response.setHeader("Access-Control-Allow-Origin","*");
        response.setHeader("Access-Control-Allow-Credentials", "true");
        response.setHeader("Access-Control-Allow-Methods", "POST, GET, PATCH, DELETE, PUT");
        response.setHeader("Access-Control-Max-Age", "3600");
        response.setHeader("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
        chain.doFilter(req, res);
    }
}

This method is based on the filter. The method is simple and clear. It is to write these response headers in the response. Many articles call you to configure the first and second methods. In fact, this is not necessary. Only one is needed.

I make complaints about it read without thorough understanding.

The third approach:

public class GoodsController {
@CrossOrigin(origins = "http://localhost:4000")
@GetMapping("goods-url")
public Response queryGoodsWithGoodsUrl(@RequestParam String goodsUrl) throws Exception {}
}  

Yes, it's the * * @ CrossOrigin * * annotation. Click to open the annotation

@Target({ ElementType.METHOD, ElementType.TYPE })
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface CrossOrigin {

}

It can be seen from the meta annotation @ Target that annotations can be placed on methods, class es, etc., similar to RequestMapping, that is, the methods under the whole controller can be controlled, or a single method can be controlled.

It can also be seen that this is the minimum granularity cors control method, accurate to the single request level.

The above three methods can solve the problem. The most commonly used ones should be the first and second. It is enough to control within the scope of several domain names. Generally, it is not necessary to be too detailed.

If these three configuration methods are used, who will take effect? Similar to the style in css and the proximity principle, understand.

Topics: Java Front-end