Three ways to solve SpringBoot cross domain

  • 2021-10-13 07:20:56
  • OfStack

Directory 1. What is cross-domain 1.1, why cross-domain problem 1.2, what is cross-domain 1.3, non-homologous restriction 1.4, how to solve cross-domain problem 2. SpringBoot solve cross-domain problem 2.1, configure CorsFilter (global cross-domain) 2.2, override WebMvcConfigurer (global cross-domain) 2.3, and use the annotation @ CrossOrigin (local cross-domain)

1. What is cross-domain

1.1. Why do cross-domain problems occur

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. A homology policy prevents javascript scripts in one domain from interacting with content in another domain. Homologous (that is, in the same domain) means that two pages have the same protocol (protocol), host (host) and port number (port)

Simply put, A application can only access the data from the background of A application, and B application can only access the data from the background of B application. If one of the protocols, ports and domain names in URL address when A application obtains data with Ajax corresponds to B application, A application is cross-domain and wants to obtain B application data, which is not allowed

1.2. What is cross-domain

If any one of the protocol, domain name and port requesting url is different from the current page url, it is cross-domain

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

1.3. Non-homologous restriction

For security reasons, the browser restricted 1 requests from accessing non-homologous URL

'1' could not read Cookie, LocalStorage, and IndexedDB for non-homologous web pages
"2" Unable to access DOM of non-homologous web pages
'3' could not send an AJAX request to a non-homologous address

1.4. How to solve cross-domain problems

The server uses pure code logic to solve cross-domain problems. If SpringBoot is used, please see the next chapter

[Tencent Document] JSONP cross-domain solution https://docs.qq.com/doc/DVEVTemdrcVVjSFlE

2. SpringBoot addresses cross-domain issues

①: Returns the new CorsFilter

②: Rewrite WebMvcConfigurer

③: Use the annotation @ CrossOrigin

Note: CorFilter/WebMvConfigurer/@ CrossOrigin needs SpringMVC version 4.2 or above to support, and the first two methods corresponding to springBoot version 1.3 or above belong to global CORS configuration, while the last two belong to local CORS configuration. If local cross-domain is used, it will override the global cross-domain rule,
Therefore, the @ CrossOrigin annotation can be used for fine-grained and higher cross-domain resource control. In fact, no matter which scheme, the ultimate goal is to modify the response header, add the data required by the browser to the response header, and then realize cross-domain

2.1. Configure CorsFilter (Global Cross Domain)


import org.springframework.boot.SpringBootConfiguration;
import org.springframework.context.annotation.Bean;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
import org.springframework.web.filter.CorsFilter;

@SpringBootConfiguration
public class WebGlobalConfig {

    @Bean
    public CorsFilter corsFilter() {

        // Create CorsConfiguration Add configuration after object 
        CorsConfiguration config = new CorsConfiguration();
        // Set which original domains are released 
        config.addAllowedOrigin("*");
        // Which original request headers are released 
        config.addAllowedHeader("*");
        // What header information is exposed 
        config.addExposedHeader("*");
        // What request methods are released 
        config.addAllowedMethod("GET");     //get
        config.addAllowedMethod("PUT");     //put
        config.addAllowedMethod("POST");    //post
        config.addAllowedMethod("DELETE");  //delete
        //corsConfig.addAllowedMethod("*");     // Release all requests 

        // Whether to send Cookie
        config.setAllowCredentials(true);

        //2.  Add mapping path 
        UrlBasedCorsConfigurationSource corsConfigurationSource =
                new UrlBasedCorsConfigurationSource();
        corsConfigurationSource.registerCorsConfiguration("/**", config);
        // Return CorsFilter
        return new CorsFilter(corsConfigurationSource);
    }
}

If you are using a higher version of SpringBoot 2.4. 4, you need to change it by 1, otherwise, the background will report an error

java.lang.IllegalArgumentException: When allowCredentials is true, allowedOrigins cannot contain the special value "*" since that cannot be set on the "Access-Control-Allow-Origin" response header. To allow credentials to a set of origins, list them explicitly or consider using "allowedOriginPatterns" instead.
at org.springframework.web.cors.CorsConfiguration.validateAllowCredentials(CorsConfiguration.java:453) ~[spring-web-5.3.6.jar:5.3.6]

When allowCredentials is true, alloedOrigins cannot contain the special value "*" because it cannot be set in the "Access-Control-Allow-Origin" response header. To allow credentials to access 1 set of sources, list them explicitly or consider using "AllowedOriginPatterns" instead.

Solution: config. addAllowedOrigin ("*"); Replace with config. addAllowedOriginPattern ("*");

2.2. Override WebMvcConfigurer (Global Cross Domain)


import org.springframework.boot.SpringBootConfiguration;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

@SpringBootConfiguration
public class CorsConfig implements WebMvcConfigurer {
    @Override
    public void addCorsMappings(CorsRegistry registry) {
        // Add mapping path 
        registry.addMapping("/**")
                // Whether to send Cookie
                .allowCredentials(true)
                // Set which original domains are released    SpringBoot2.4.4 Use the lower version .allowedOrigins("*")    
                .allowedOriginPatterns("*")
                // What request methods are released 
                .allowedMethods(new String[]{"GET", "POST", "PUT", "DELETE"})
                //.allowedMethods("*") // Or release all of them 
                // Which original request headers are released 
                .allowedHeaders("*")
                // What raw request header information is exposed 
                .exposedHeaders("*");
    }
}

2.3. Use the annotation @ CrossOrigin (local cross-domain)


@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface CrossOrigin {
    // This origins And value Yes 1 Like 
    // A list of allowed source domain names, such as  'www.jd.com' The matching domain name is a cross-domain pre-request  Response  In the head 'Access-Control-Aloow_origin' 
    // Field value. Cross-domain access of all domain names is supported by default when the exact value is not set. 
    @AliasFor("origins")
    String[] value() default {};
    @AliasFor("value")
    String[] origins() default {};
    // Under the high version Spring2.4.4 Use originPatterns  Instead of value  And  origins
    String[] originPatterns() default {};

    // The type of field in the request header allowed in a cross-domain request,   This value corresponds to cross-domain pre-request  Response  In the head  'Access-Control-Allow-Headers'  Field value. 
    // Do not set the exact value. All of them are supported by default header Fields ( Cache-Controller , Content-Language , Content-Type , 
    //Expires , Last-Modified , Pragma ) Cross-domain access 
    String[] allowedHeaders() default {};

    // Division allowed in cross-domain request header Cache-Controller , Content-Language , Content-Type , Expires , Last-Modified , 
    //Pragma This 6 Field information other than basic fields, corresponding to cross-domain requests  Response  In the head  'Access-control-Expose-Headers' Field value 
    String[] exposedHeaders() default {};

    // Cross-domain HTTP Supported in the request HTTP Request type ( GET , POST... ), the default is the same as when the exact value is not specified  Controller  Method in the  methods  Field retention 1 To. 
    RequestMethod[] methods() default {};

    // This value corresponds to a cross-domain request  Response  In the head  'Access-Control-Allow-Credentials'  Field value. 
    // Does the browser set the  cookie  Information is carried to cross-domain servers. It is carried to cross-domain servers by default, but it is necessary to implement  cookie 
    // Sharing also requires the front end to be in  AJAX  Open on request  withCredentials  Property. 
    String allowCredentials() default "";

    // This value corresponds to a cross-domain request  Response  In the head  'Access-Control-Max-Age'  Field that represents the maximum cache duration of the preview request response, 
    // The aim is to reduce browser preview requests / Number of response interactions. Default value 1800s . When this value is set, the browser will no longer initiate a pre-request for the cross-domain request for the time period for which the value is set 
    long maxAge() default -1;
}

①: Use the @ CrossOrigin annotation on the controller (on the class) to indicate that all methods of the class are allowed to cross domains


@Controller
@RequestMapping("/shop")
@CrossOrigin(originPatterns = "*", methods = {RequestMethod.GET, RequestMethod.POST})
public class ShopController {
    
    @GetMapping("/")
    @ResponseBody
    public Map<String, Object> findAll() {
        // Return data 
        return DataSchool.getStudents();
    }
}

② We can also set smaller granularity and set cross-domain on the method


@Controller
@RequestMapping("/shop")
public class ShopController {

    @GetMapping("/")
    @ResponseBody
    // Smaller solution across domains   Set access only to certain addresses 
    @CrossOrigin(originPatterns = "http://localhost:8080")
    public Map<String, Object> findAll() {
        // Return data 
        return DataSchool.getStudents();
    }
}

The above is to solve the SpringBoot cross-domain of the details of the three ways, more information about SpringBoot cross-domain please pay attention to the site of other related articles!


Related articles: