Spring cors

Encountered a problem today, spring is configured cors no effect. The original is because they were intercepted spring security deal. CorsFilter arranged after the filter chain Spring security, and the configuration is by WebMvcConfigurationSupport CorsConfiguration, but later in the Spring MVC Spring security filter chain, so there is no effect. CORS will add the filter of the filter chain by configuring Spring Security CorsConfigurationSource.

Spring Security documents say:
CORS configuration easiest way is by adding Spring CorsFilter, may be used to make the spring security cors configure CorsConfigurationSource, so that the filter chain will CorsFilter applied in Spring Security.

I found:
in Spring webFlux security, if their definition CorsFitler, must be guaranteed before the filter chain Spring security, so that it will not be intercepted Spring Security processing, thus there is no Cors filter. Will be processed before the filter chain Spring security is @Order (Ordered.HIGHEST_PRECEDENCE) by specifying the filter Order.

And you can specify CorsFilter directly in Spring Web Security, Spring security will directly use the existing CorsFilter.
https://docs.spring.io/spring-security/site/docs/4.2.x/reference/html/cors.html

Spring Web flow Cors

Spring webflux security look how cors applied to the filter in the chain:
in http.build () in

  if (this.cors != null) {
    this.cors.configure(this);
  }
protected void configure(ServerHttpSecurity http) {
  CorsWebFilter corsFilter = this.getCorsFilter();
  if (corsFilter != null) {
    http.addFilterAt(this.corsFilter, SecurityWebFiltersOrder.CORS);
  }

}
private CorsWebFilter getCorsFilter() {
  if (this.corsFilter != null) {
    return this.corsFilter;
  } else {
    CorsConfigurationSource source = (CorsConfigurationSource)ServerHttpSecurity.this.getBeanOrNull(CorsConfigurationSource.class);
    if (source == null) {
      return null;
    } else {
      CorsProcessor processor = (CorsProcessor)ServerHttpSecurity.this.getBeanOrNull(CorsProcessor.class);
      if (processor == null) {
        processor = new DefaultCorsProcessor();
      }

      this.corsFilter = new CorsWebFilter(source, (CorsProcessor)processor);
      return this.corsFilter;
    }
  }
}

And by ServerHttpSecurity.this.getBeanOrNull()obtaining a container bean method, thereby acquiring CorsConfigurationSource instances where configuration CORS.

Spring Web Security Cors

In the spring web security seems to spring security CorsFilter can be identified and used, there is no actual tested.

  @Override
  protected void configure(HttpSecurity http) throws Exception {
    http
        .csrf().disable()
        .cors().disable()
        .httpBasic().disable()
        .formLogin().disable()
        .addFilterBefore(jwtAuthorizationFilter, UsernamePasswordAuthenticationFilter.class)
        .authorizeRequests()
        .antMatchers("/actuator/**").permitAll()
        .antMatchers(
            "/company/user/check/**",
        ).permitAll()
        .anyRequest().authenticated()
        .and()
        .exceptionHandling().authenticationEntryPoint(defaultAuthenticationEntryPoint);
  }

In class HttpSecurity

  public CorsConfigurer<HttpSecurity> cors() throws Exception {
    return (CorsConfigurer)this.getOrApply(new CorsConfigurer());
  }

Spring web security CorsConfigurer中:

  private CorsFilter getCorsFilter(ApplicationContext context) {
    if (this.configurationSource != null) {
      return new CorsFilter(this.configurationSource);
    } else {
      boolean containsCorsFilter = context.containsBeanDefinition("corsFilter");
      if (containsCorsFilter) {
        return (CorsFilter)context.getBean("corsFilter", CorsFilter.class);
      } else {
        boolean containsCorsSource = context.containsBean("corsConfigurationSource");
        if (containsCorsSource) {
          CorsConfigurationSource configurationSource = (CorsConfigurationSource)context.getBean("corsConfigurationSource", CorsConfigurationSource.class);
          return new CorsFilter(configurationSource);
        } else {
          boolean mvcPresent = ClassUtils.isPresent("org.springframework.web.servlet.handler.HandlerMappingIntrospector", context.getClassLoader());
          return mvcPresent ? CorsConfigurer.MvcCorsFilter.getMvcCorsFilter(context) : null;
        }
      }
    }
  }

First check CorsFilter, then check CorsConfigurationSource bean.
In this case provided directly CorsFilter spring security can be added to the filter chain.

Spring mvc Cors

Spring MVC documents say:
Spring MVC HandlerMapping realization of built-in support CORS, after successfully mapped a request to a handler, HandlerMapping checks the CORS configuration to take the next action.
https://docs.spring.io/spring/docs/current/spring-framework-reference/web.html#mvc-cors-processing

My findings:
the Spring MVC will be checked after finding the handler CORS configuration by adding a blocker.
Spring MVC is the CORS After finding hander, this is after the filter chain Spring security, so cors no effect.

The following look at Spring MVC realization of the CORS.
DispatcherServlet call getHandler AbstractHandlerMapping in () method:

  public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
    Object handler = this.getHandlerInternal(request);
    if (handler == null) {
      handler = this.getDefaultHandler();
    }

    if (handler == null) {
      return null;
    } else {
      if (handler instanceof String) {
        String handlerName = (String)handler;
        handler = this.obtainApplicationContext().getBean(handlerName);
      }

      HandlerExecutionChain executionChain = this.getHandlerExecutionChain(handler, request);
      if (this.logger.isTraceEnabled()) {
        this.logger.trace("Mapped to " + handler);
      } else if (this.logger.isDebugEnabled() && !request.getDispatcherType().equals(DispatcherType.ASYNC)) {
        this.logger.debug("Mapped to " + executionChain.getHandler());
      }

      if (CorsUtils.isCorsRequest(request)) {
        CorsConfiguration globalConfig = this.corsConfigurationSource.getCorsConfiguration(request);
        CorsConfiguration handlerConfig = this.getCorsConfiguration(handler, request);
        CorsConfiguration config = globalConfig != null ? globalConfig.combine(handlerConfig) : handlerConfig;
        executionChain = this.getCorsHandlerExecutionChain(request, executionChain, config);
      }

      return executionChain;
    }
  }

Automatically add a cors interceptor:

  protected HandlerExecutionChain getCorsHandlerExecutionChain(HttpServletRequest request, HandlerExecutionChain chain, @Nullable CorsConfiguration config) {
    if (CorsUtils.isPreFlightRequest(request)) {
      HandlerInterceptor[] interceptors = chain.getInterceptors();
      chain = new HandlerExecutionChain(new AbstractHandlerMapping.PreFlightHandler(config), interceptors);
    } else {
      chain.addInterceptor(new AbstractHandlerMapping.CorsInterceptor(config));
    }

    return chain;
  }
 private class CorsInterceptor extends HandlerInterceptorAdapter implements CorsConfigurationSource {
    @Nullable
    private final CorsConfiguration config;

    public CorsInterceptor(@Nullable CorsConfiguration config) {
      this.config = config;
    }

    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
      return AbstractHandlerMapping.this.corsProcessor.processRequest(this.config, request, response);
    }

    @Nullable
    public CorsConfiguration getCorsConfiguration(HttpServletRequest request) {
      return this.config;
    }
  }

DefaultCorsProcessor

  public boolean processRequest(@Nullable CorsConfiguration config, HttpServletRequest request, HttpServletResponse response) throws IOException {
    if (!CorsUtils.isCorsRequest(request)) {
      return true;
    } else {
      ServletServerHttpResponse serverResponse = new ServletServerHttpResponse(response);
      if (this.responseHasCors(serverResponse)) {
        logger.trace("Skip: response already contains \"Access-Control-Allow-Origin\"");
        return true;
      } else {
        ServletServerHttpRequest serverRequest = new ServletServerHttpRequest(request);
        if (WebUtils.isSameOrigin(serverRequest)) {
          logger.trace("Skip: request is from same origin");
          return true;
        } else {
          boolean preFlightRequest = CorsUtils.isPreFlightRequest(request);
          if (config == null) {
            if (preFlightRequest) {
              this.rejectRequest(serverResponse);
              return false;
            } else {
              return true;
            }
          } else {
            return this.handleInternal(serverRequest, serverResponse, config, preFlightRequest);
          }
        }
      }
    }
  }

dispatcherServlet call interceptor before the actual Handler the Invoke:
the doDispatch method:

  HandlerAdapter ha = this.getHandlerAdapter(mappedHandler.getHandler());
  String method = request.getMethod();
  boolean isGet = "GET".equals(method);
  if (isGet || "HEAD".equals(method)) {
    long lastModified = ha.getLastModified(request, mappedHandler.getHandler());
    if ((new ServletWebRequest(request, response)).checkNotModified(lastModified) && isGet) {
      return;
    }
  }

  if (!mappedHandler.applyPreHandle(processedRequest, response)) {
    return;
  }

  mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
  if (asyncManager.isConcurrentHandlingStarted()) {
    return;
  }

Thereby preventing the request by adding cors interceptor.

Guess you like

Origin www.cnblogs.com/helloz/p/10961039.html