• Spring cors


    今天遇到一个问题,就是spring中配置cors没有效果。原来是因为被spring security拦截处理了。配置了CorsFilter在Spring security过滤器链之后,而通过WebMvcConfigurationSupport配置的CorsConfiguration则是Spring MVC中的, 更是在Spring security过滤器链的后面, 因此没有效果。而通过配置CorsConfigurationSource则会在Spring Security的过滤链中加上CORS过滤器。

    Spring security的文档这样说:
    Spring中添加CORS配置最简单的方法是通过CorsFilter, 也可以通过配置CorsConfigurationSource来使spring security使用cors, 这样会把CorsFilter加到Spring security的过滤器链中。

    我的发现:
    在Spring webFlux security中, 如果自己定义CorsFitler, 必须保证在Spring security的过滤器链之前, 这样才不会被Spring Security拦截处理, 从而没有了Cors过滤器。通过指定过滤器的Order为 @Order(Ordered.HIGHEST_PRECEDENCE)会在Spring security的过滤器链之前处理。

    而在Spring Web Security 中则可以直接指定CorsFilter, Spring security会直接使用已有的CorsFilter。
    https://docs.spring.io/spring-security/site/docs/4.2.x/reference/html/cors.html

    Spring Web Flux Cors

    看下Spring webflux security是如何把cors加到过滤器链中的:
    在http.build()中

      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;
    	}
      }
    }
    

    而通过ServerHttpSecurity.this.getBeanOrNull()方法获取容器中的bean, 从而在这里获取CorsConfigurationSource实例配置CORS。

    Spring Web Security Cors

    而在spring web security中似乎spring security是可以识别CorsFilter并使用的, 这里没有实际测试过。

      @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);
      }
    

    而在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;
            }
          }
        }
      }
    

    首先检查CorsFilter, 然后检查CorsConfigurationSource bean。
    此时直接设置CorsFilter是可以加到spring security过滤器链中的。

    Spring mvc Cors

    Spring MVC的文档这样说:
    Spring MVC 的HandlerMapping实现内置支持CORS, 在成功映射一个请求到一个handler之后, HandlerMapping会检查CORS配置以采取下一步动作。
    https://docs.spring.io/spring/docs/current/spring-framework-reference/web.html#mvc-cors-processing

    我的发现:
    Spring MVC会在找到handler后通过添加一个拦截器来检查CORS配置。
    Spring MVC的CORS是在找到hander之后, 这个更是在Spring security的过滤器链之后, 从而cors没有效果。

    下面来看一下Spring MVC中的CORS的实现。
    DispatcherServlet调用AbstractHandlerMapping中的getHandler()方法:

      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;
        }
      }
    

    自动加上一个cors的拦截器:

      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中在真正invoke handler之前调用拦截器:
    doDispatch方法:

      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;
      }
    

    从而通过加的cors拦截器阻止请求。

  • 相关阅读:
    bzoj 2152: 聪聪可可
    bzoj 2143: 飞飞侠
    bzoj 2132: 圈地计划
    bzoj 2127: happiness
    bzoj 2124: 等差子序列
    bzoj 2120: 数颜色
    对MySQL数据类型的认识
    MySQL详解--锁,事务(转)
    mysql 5.7快速部署
    elasticsearch报错[WARN ][bootstrap ] Unable to lock JVM Memory: error=12,reason=Cannot allocate memory,解决
  • 原文地址:https://www.cnblogs.com/helloz/p/10961039.html
Copyright © 2020-2023  润新知