spring MVC cors 크로스 필드 에서 소스 코드 분석 실현

12168 단어 cors크로스 필드
명사 해석:크로스-오리 진 리 소스 공유
쉽게 말 하면 프로 토 콜,IP,http 방법 이 임의로 다 르 면 크로스 필드 입 니 다.
spring MVC 는 4.2 부터 도 메 인 간 지원 을 추가 합 니 다.
크로스 필드 의 구체 적 인 정 의 는 이동 하 십시오mozilla보 세 요.
사용 사례
spring mvc 에서 도 메 인 을 넘 어 사용 하 는 방법 은 세 가지 가 있 습 니 다.
웹.xml 에 CorsFilter 설정

<filter>
 <filter-name>cors</filter-name>
 <filter-class>org.springframework.web.filter.CorsFilter</filter-class>
</filter>
<filter-mapping>
 <filter-name>cors</filter-name>
 <url-pattern>/*</url-pattern>
</filter-mapping>
xml 에 설정

//     ,          ,      
<mvc:cors> 
 <mvc:mapping path="/**" /> 
</mvc:cors> 
//         
<mvc:cors> 
 <mvc:mapping path="/api/**" 
  allowed-origins="http://domain1.com, http://domain2.com" 
  allowed-methods="GET, PUT" 
  allowed-headers="header1, header2, header3" 
  exposed-headers="header1, header2" allow-credentials="false" 
  max-age="123" /> 
  <mvc:mapping path="/resources/**" 
  allowed-origins="http://domain1.com" /> 
</mvc:cors> 
주 해 를 사용 하 다

@CrossOrigin(maxAge = 3600) 
@RestController 
@RequestMapping("/account") 
public class AccountController { 
 @CrossOrigin("http://domain2.com") 
 @RequestMapping("/{id}") 
 public Account retrieve(@PathVariable Long id) { 
  // ... 
 } 
} 
개념 에 관련되다
  • CorsConfiguration 에서 크로스 도 메 인 설정 정 보 를 구체 적 으로 밀봉 한 pojo
  • CorsConfigurationSource request 와 도 메 인 설정 정보 맵 의 용기
  • CorsProcessor 가 구체 적 으로 크로스 오 버 작업 을 하 는 유형
  • 노 간 크로스 도 메 인 설정 정보 초기 화 류
  • 노 간 크로스 도 메 인 에서 사용 하 는 Adapter
  • 관련 자바 클래스:
    봉 인 된 메시지 의 pojo
    CorsConfiguration
    request 와 크로스 필드 설정 정 보 를 저장 하 는 용기
    CorsConfigurationSource、UrlBasedCorsConfigurationSource
    구체 적 처리 류
    CorsProcessor、DefaultCorsProcessor
    CorsUtils
    OncePerRequestFilter 인 터 페 이 스 를 실현 하 는 Adapter
    CorsFilter
    request 가 cors 인지 확인 하고 대응 하 는 Adapter 를 패키지 합 니 다.
    AbstractHandler Mapping,내부 클래스 PreFlightHandler,CorsInterceptor 포함
    CrossOrigin 주석 정보 읽 기
    AbstractHandlerMethodMapping、RequestMappingHandlerMapping
    xml 파일 에서 크로스 필드 설정 정 보 를 읽 습 니 다.
    CorsBeanDefinitionParser
    크로스 도 메 인 등록 보조 클래스
    MvcNamespaceUtils
    debug 분석
    코드 를 알 아 보 려 면 도 메 인 정 보 를 봉인 하 는 pojo--CorsConfiguration 을 알 아야 합 니 다.
    여 기 는 매우 간단 한 pojo 입 니 다.도 메 인 에 대응 하 는 몇 가지 속성 을 제외 하고 combine,checkOrigin,checkHttpMethod,checkHeaders 만 있 습 니 다.
    속성 은 모두 다수 치 조합 에서 사용 합 니 다.
    
     // CorsConfiguration
     public static final String ALL = "*";
     //       
     private List<String> allowedOrigins;
     //    http  
     private List<String> allowedMethods;
     //       
     private List<String> allowedHeaders;
     //       
     private List<String> exposedHeaders;
     //       cookies
     private Boolean allowCredentials;
     //          
     private Long maxAge;
    combine 은 도 메 인 정 보 를 통합 하 는 것 입 니 다.
    3 개의 check 방법 은 각각 request 의 정보 가 허용 범위 내 에 포함 되 어 있 는 지 확인 하 는 것 이다.
    설정 초기 화
    시스템 이 시 작 될 때 CorsBeanDefinitionParser 를 통 해 설정 파일 을 분석 합 니 다.
    RequestMappingHandlerMapping 을 불 러 올 때 InitialingBean 의 after Properties 갈 고 리 를 통 해 initCorsConfiguration 을 호출 하여 주석 정 보 를 초기 화 합 니 다.
    프로필 초기 화
    CorsBean Definition Parser 류 의 parse 방법 에서 정지점 을 찍 습 니 다.


    CorsBean Definition Parser 호출 스 택
    코드 를 통 해 이쪽 해석 을 볼 수 있 습 니 다.
    크로스 필드 정보의 설정 은 path 단위 로 여러 맵 관 계 를 정의 할 수 있 습 니 다.
    분석 할 때 정의 가 없 으 면 기본 설정 을 사용 합 니 다.
    
    // CorsBeanDefinitionParser
    if (mappings.isEmpty()) {
     //           
     CorsConfiguration config = new CorsConfiguration();
     config.setAllowedOrigins(DEFAULT_ALLOWED_ORIGINS);
     config.setAllowedMethods(DEFAULT_ALLOWED_METHODS);
     config.setAllowedHeaders(DEFAULT_ALLOWED_HEADERS);
     config.setAllowCredentials(DEFAULT_ALLOW_CREDENTIALS);
     config.setMaxAge(DEFAULT_MAX_AGE);
     corsConfigurations.put("/**", config);
    }else {
     //   mapping   
     for (Element mapping : mappings) {
      CorsConfiguration config = new CorsConfiguration();
      if (mapping.hasAttribute("allowed-origins")) {
       String[] allowedOrigins = StringUtils.tokenizeToStringArray(mapping.getAttribute("allowed-origins"), ",");
       config.setAllowedOrigins(Arrays.asList(allowedOrigins));
      }
      // ...
     }
    분석 완료 후 MvcNamespaceUtils.registerCorsConfigurations 를 통 해 등록
    이쪽 은 spring bean 용기 관리의 통 일 된 절 차 를 밟 고 있 으 며,지금 은 Bean Definition 으로 바 뀌 어 예화 되 었 습 니 다.
    
    // MvcNamespaceUtils
     public static RuntimeBeanReference registerCorsConfigurations(Map<String, CorsConfiguration> corsConfigurations, ParserContext parserContext, Object source) {
      if (!parserContext.getRegistry().containsBeanDefinition(CORS_CONFIGURATION_BEAN_NAME)) {
       RootBeanDefinition corsConfigurationsDef = new RootBeanDefinition(LinkedHashMap.class);
       corsConfigurationsDef.setSource(source);
       corsConfigurationsDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
       if (corsConfigurations != null) {
        corsConfigurationsDef.getConstructorArgumentValues().addIndexedArgumentValue(0, corsConfigurations);
       }
       parserContext.getReaderContext().getRegistry().registerBeanDefinition(CORS_CONFIGURATION_BEAN_NAME, corsConfigurationsDef);
       parserContext.registerComponent(new BeanComponentDefinition(corsConfigurationsDef, CORS_CONFIGURATION_BEAN_NAME));
      }
      else if (corsConfigurations != null) {
       BeanDefinition corsConfigurationsDef = parserContext.getRegistry().getBeanDefinition(CORS_CONFIGURATION_BEAN_NAME);   corsConfigurationsDef.getConstructorArgumentValues().addIndexedArgumentValue(0, corsConfigurations);
      }
      return new RuntimeBeanReference(CORS_CONFIGURATION_BEAN_NAME);
     }
    주석 초기 화
    Request Mapping Handler Mapping 의 initCorsConfiguration 에서 CrossOrigin 주 해 를 사용 하 는 방법 을 스 캔 하고 정 보 를 추출 합 니 다.

    RequestMappingHandlerMapping_initCorsConfiguration
    
    // RequestMappingHandlerMapping
     @Override
     protected CorsConfiguration initCorsConfiguration(Object handler, Method method, RequestMappingInfo mappingInfo) {
      HandlerMethod handlerMethod = createHandlerMethod(handler, method);
      CrossOrigin typeAnnotation = AnnotatedElementUtils.findMergedAnnotation(handlerMethod.getBeanType(), CrossOrigin.class);
      CrossOrigin methodAnnotation = AnnotatedElementUtils.findMergedAnnotation(method, CrossOrigin.class);
      if (typeAnnotation == null && methodAnnotation == null) {
       return null;
      }
      CorsConfiguration config = new CorsConfiguration();
      updateCorsConfig(config, typeAnnotation);
      updateCorsConfig(config, methodAnnotation);
      // ...      
      return config;
     } 
    
    크로스 필드 요청 처리
    Handler Mapping 은 검색 프로 세 서 를 정상적으로 처리 한 후 Abstract Handler Mapping.getHandler 에서 크로스 도 메 인 요청 인지 확인 하고 두 가지 로 나 누 어 처리 합 니 다.
  • 사전 요청 이 라면 내부 클래스 PreFlightHandler 로 처리 장 치 를 교체 합 니 다
  • 정상 적 인 요청 이 라면 CorsInterceptor 차단 기 를 추가 합 니 다
  • 프로 세 서 를 가 져 온 후 요청 헤더 에 Origin 이 포함 되 어 있 는 지 여 부 를 판단 합 니 다.크로스 필드 라면 UrlBasedCorsConfigurationSource 를 통 해 크로스 필드 설정 정 보 를 가 져 오고 getCorsHandlerExecutionChain 에 의뢰 합 니 다.
    UrlBasedCorsConfigurationSource 는 CorsConfigurationSource 의 실현 으로 클래스 이름 에서 이 request 와 CorsConfiguration 의 매 핑 은 url 에 기반 한 것 으로 추측 할 수 있 습 니 다.getCorsConfiguration 에서 request 의 url 을 추출 한 후 url 과 일치 하 는 지 확인 합 니 다.
    
     // UrlBasedCorsConfigurationSource
     public CorsConfiguration getCorsConfiguration(HttpServletRequest request) {
      String lookupPath = this.urlPathHelper.getLookupPathForRequest(request);
      for(Map.Entry<String, CorsConfiguration> entry : this.corsConfigurations.entrySet()) {
       if (this.pathMatcher.match(entry.getKey(), lookupPath)) {
        return entry.getValue();
       }
      }
      return null;
     }
     // AbstractHandlerMapping
     public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
      Object handler = getHandlerInternal(request);
      // ...
      HandlerExecutionChain executionChain = getHandlerExecutionChain(handler, request);
      if (CorsUtils.isCorsRequest(request)) {
       CorsConfiguration globalConfig = this.corsConfigSource.getCorsConfiguration(request);
       CorsConfiguration handlerConfig = getCorsConfiguration(handler, request);
       CorsConfiguration config = (globalConfig != null ? globalConfig.combine(handlerConfig) : handlerConfig);
       executionChain = getCorsHandlerExecutionChain(request, executionChain, config);
      }
      return executionChain;
     }
     // HttpHeaders
     public static final String ORIGIN = "Origin";
     // CorsUtils
     public static boolean isCorsRequest(HttpServletRequest request) {
      return (request.getHeader(HttpHeaders.ORIGIN) != null);
     }
    
    요청 헤더 의 http 방법 을 통 해 options 가 사전 요청 여 부 를 판단 할 지 여부 입 니 다.PreFlightRequest 를 사용 하여 프로 세 서 를 교체 하 는 경우;일반적인 요청 이 라면 차단 기 를 추가 합 니 다.
    PreFlightRequest 는 CorsProcessor 가 HttpRequestHandler 에 대한 어댑터 입 니 다.이렇게 HandlerAdapter 는 HttpRequestHandlerAdapter 를 직접 사용 하여 처리 합 니 다.
    CorsInterceptor 는 CorsProcessor 가 Hnalder Interceptor Adapter 에 대한 어댑터 입 니 다.
    
     // AbstractHandlerMapping
     protected HandlerExecutionChain getCorsHandlerExecutionChain(HttpServletRequest request,
       HandlerExecutionChain chain, CorsConfiguration config) {
      if (CorsUtils.isPreFlightRequest(request)) {
       HandlerInterceptor[] interceptors = chain.getInterceptors();
       chain = new HandlerExecutionChain(new PreFlightHandler(config), interceptors);
      }
      else {
       chain.addInterceptor(new CorsInterceptor(config));
      }
      return chain;
     }
     private class PreFlightHandler implements HttpRequestHandler {
      private final CorsConfiguration config;
      public PreFlightHandler(CorsConfiguration config) {
       this.config = config;
      }
      @Override
      public void handleRequest(HttpServletRequest request, HttpServletResponse response)
        throws IOException {
    
       corsProcessor.processRequest(this.config, request, response);
      }
     }
     private class CorsInterceptor extends HandlerInterceptorAdapter {
      private final CorsConfiguration config;
      public CorsInterceptor(CorsConfiguration config) {
       this.config = config;
      }
      @Override
      public boolean preHandle(HttpServletRequest request, HttpServletResponse response,
        Object handler) throws Exception {
    
       return corsProcessor.processRequest(this.config, request, response);
      }
     }
     // CorsUtils
     public static boolean isPreFlightRequest(HttpServletRequest request) {
      return (isCorsRequest(request) && request.getMethod().equals(HttpMethod.OPTIONS.name()) &&
        request.getHeader(HttpHeaders.ACCESS_CONTROL_REQUEST_METHOD) != null);
     }
    
    github 에 가서 볼 수 있 습 니 다https://github.com/haplone/spring_doc/blob/master/mvc/cors.md
    이상 은 본 고의 모든 내용 입 니 다.본 고의 내용 이 여러분 의 학습 이나 업무 에 어느 정도 도움 이 되 기 를 바 랍 니 다.또한 저 희 를 많이 지지 해 주시 기 바 랍 니 다!

    좋은 웹페이지 즐겨찾기