Moment For Technology

SpringBoot elegantly configures multiple ways to cross domains and Spring Security cross-domain access configuration pits | More articles in August challenges

Posted on Oct. 3, 2022, 5:39 a.m. by 朱志偉
Category: The back-end Tag: The back-end Spring Boot

This is the 14th day of my participation in the August More Text Challenge

preface

When I was working on a project recently, Spring Security was used as permission control management in the background based on the authority management system with the separation of the front and back ends, and then cross-domain was involved in the access of the front-end interface. However, cross-domain configuration did not take effect. There was a pit here, which was configured separately when Spring Security was used. SpringBoot traversal is not feasible, but you need to configure Security across domains.

What is cross-domain

Cross-domain is a browser same-origin security policy, that is, the browser unilaterally restricts the cross-domain access of scripts

In HTML, tags such as ,

, ,

A difference between the current page URL and the requested URL header (before the port) can cause cross-domain. Colloquially speaking, it is two URLS, the part before the port, as long as there is a little difference that occurs across domains.

Such as:

1. Accessing https://a.baidu.com resources at http://a.baidu.com creates a cross-domain protocol. 2. Access b.baidu.com resources under a.baidu.com, creating host cross-domains. 3. Access A.baidu.com :8080 from a.baidu.com:80 resources form inter-domain ports.Copy the code

Common ways to solve cross-domain problems

JSONP

Because browsers allow some tags with SRC attributes to cross domains, such as iframe, script, img, etc., JSONP can use script tags to cross domains

The front end requests through the Script tag and specifies in the callback the name of the returned wrapper entity as JSONP (customizable)

script src="http://aaa.com/getusers?callback=jsonp"/script
Copy the code

The back end wraps the returned results in the desired data format

jsonp({
    "error":200."message":"Request successful"."data": [{"username":"Zhang"."age":20}]})Copy the code

Summary: JSONP is simple to implement, but it only supports GET requests across domains, which has major limitations

CORS

CORS, or Cross-Origin Resource Sharing, is a W3C standard that allows browsers to issue XMLHttpRequest requests to cross-source servers, overcoming the limitation that AJAX can only be used in the same source.

There is a new set of HTTP Header fields in the specification that inform clients of cross-domain limits by adding a special Header[access-Control-Allow-Origin] to the server. If the browser supports CORS and determines that Origin has passed, It allows XMLHttpRequest to make a cross-domain request

Note: CORS does not support browsers below IE8

| | CORS Header attribute interpretation | | : -- -- -- -- -- -- -- -- - | : - : | -- -- -- -- -- -- -- -- -- -- - : | | Access - Control - Allow - Origin | allows www.xxx.com domain (to set, Here only do sample) launched a cross-domain request | Access - Control - Max - Age | set up in 86400 seconds don't need to send the divverify request | Access - Control - Allow - the Methods | Settings Allow cross-domain request method | Access - Control - Allow - Headers | Allow cross-domain request contains the content-type | Access - Control - Allow - Credentials | Settings to Allow cookies

SpringBoot solves the leapfrog approach

@ CrossOrigin annotations

This is SpringBoot with annotations, very simple to use, just need to add the last annotation in the corresponding interface line

"Origins = "*" indicates that all IP addresses can access the interface, or a specific address can be written, indicating that only this IP address can access the interface

You can annotate on a class, and on a method, class to indicate that all interfaces of this Controller support cross-domain, and on a single method to indicate that only this interface supports cross-domain

Although this method is elegant and simple, the disadvantage is also not small, which requires cross-domain interfaces to add this annotation, which is not friendly to the project of front and back end separation, need to add many times, so this method is rarely used

Interceptor mode

Override the addCorsMappings method of WebMvcConfigurer

@Configuration
public class CorsConfig implements WebMvcConfigurer {
    @Override
    public void addCorsMappings(CorsRegistry registry) {
        registry.addMapping("/ * *")// All interfaces in the project are cross-domain supported
                .allowedOriginPatterns("*")// All addresses can be accessed, and specific addresses can also be configured
                .allowCredentials(true)
                .allowedMethods("*")//"GET", "HEAD", "POST", "PUT", "DELETE", "OPTIONS"
                .maxAge(3600);// Allow time across domains}}Copy the code

Note that allowedOrigins("*") and allowCredentials(true) are incorrect when set to true and need to be changed to allowedOriginPatterns("*") or specify the interface allowedOrigins(" HTTP // WWW. baidu.com")

@Configuration indicates a Configuration class that is loaded when the project is started. Implement the WebMvcConfigurer interface and rewrite the addCorsMappings method. The code is simple and annotated

Filter Filter mode

  1. Methods a
@Bean
    public CorsFilter corsFilter(a) {
         //1. Add CORS configuration information
        CorsConfiguration config = new CorsConfiguration();
          // Which primitive fields are allowed
          config.addAllowedOrigin("*");
          // Whether to send Cookie information
          config.setAllowCredentials(true);
          // Which primitive fields are allowed (request mode)
          config.addAllowedMethod("*");
          // Which raw fields are allowed (header information)
          config.addAllowedHeader("*");
          // Which headers to expose (because cross-domain access does not get all headers by default)
          config.addExposedHeader("*");

        //2. Add a mapping path
        UrlBasedCorsConfigurationSource configSource = new UrlBasedCorsConfigurationSource();
        configSource.registerCorsConfiguration("/ * *", config);

        //3. Return a new CorsFilter.
        return new CorsFilter(configSource);
    }
Copy the code
  1. Way 2

Based on the original configuration of the Servler

@Slf4j @Component public class CorsFilter implements Filter { @Override public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException { HttpServletResponse response = (HttpServletResponse)servletResponse; response.setHeader("Access-Control-Allow-Origin", "*"); response.setHeader("Access-Control-Allow-Methods", "POST, PUT, GET, OPTIONS, DELETE"); response.setHeader("Access-Control-Max-Age", "3600"); response.setHeader("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept, client_id, uuid, Authorization"); response.setHeader("Cache-Control", "no-cache, no-store, must-revalidate"); response.setHeader("Pragma", "no-cache"); filterChain.doFilter(servletRequest,response); }}Copy the code

The above three methods can solve the problem, the most commonly used should be the first, the second, control in their own domain name scope is enough, generally there is no need to make too fine.

If all three configuration methods are used, which one will take effect, similar to CSS style, proximity principle, get the idea

Spring Security enables CORS support

If Spring Security is configured for your project, you need to specify Spring Security across domains separately

Otherwise the crossing will not take effect

Spring Security provides excellent support for CORS, simply by enabling CORS support in the configurator and writing a CORS configuration source

@Override
    protected void configure(HttpSecurity http) throws Exception {
        // We don't need CSRF for this example
        http.cors().and().csrf().disable()
                // dont authenticate this particular request
                .authorizeRequests().antMatchers("/"."/*.html"."/favicon.ico"."/css/**"."/js/**"."/fonts/**"."/layui/**"."/img/**"."/v3/api-docs/**"."/swagger-resources/**"."/webjars/**"."/pages/**"."/druid/**"."/statics/**"."/login"."/register").permitAll().
                // all other requests need to be authenticated
                        anyRequest().authenticated().and().
                // make sure we use stateless session; session won't be used to
                // store user's state.
                // Override the default login
                        exceptionHandling().authenticationEntryPoint(jwtAuthenticationEntryPoint).and().sessionManagement()
                // Token-based, so no session is required
                .sessionCreationPolicy(SessionCreationPolicy.STATELESS);


        // Add a filter to validate the tokens with every request
        http.addFilterBefore(jwtRequestFilter, UsernamePasswordAuthenticationFilter.class);
    }
    
    @Bean
    public CorsFilter corsFilter(a) {
        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();

        CorsConfiguration corsConfiguration = new CorsConfiguration();
        corsConfiguration.addAllowedOriginPattern("*");
        corsConfiguration.addAllowedHeader("*");
        corsConfiguration.addAllowedMethod("*");
        corsConfiguration.setAllowCredentials(true);
        source.registerCorsConfiguration("/ * *", corsConfiguration);
        return new CorsFilter(source);
    }

Copy the code
Search
About
mo4tech.com (Moment For Technology) is a global community with thousands techies from across the global hang out!Passionate technologists, be it gadget freaks, tech enthusiasts, coders, technopreneurs, or CIOs, you would find them all here.