ホームページ Java &#&チュートリアル Spring MVC cors クロスドメイン実装ソースコードのサンプルコード分析

Spring MVC cors クロスドメイン実装ソースコードのサンプルコード分析

Mar 09, 2017 am 10:27 AM
cors mvc spring

この記事では主にSpring MVC corsのクロスドメイン実装のソースコード解析を紹介します。非常に優れた参考値です。以下のエディターで見てみましょう

用語の説明: Cross-Origin Resource Sharing

簡単に言うと、プロトコル、IP、httpメソッドが異なっていれば、クロスドメインです。

spring MVC は 4.2 以降、クロスドメインのサポートを追加しました。

クロスドメインの具体的な定義については、mozilla にアクセスして

ユースケース

Spring MVC でクロスドメインを使用するには 3 つの方法があります:

Web で CorsFilter を構成する注釈を使用して xml で構成された .xml

<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>
ログイン後にコピー

// 简单配置,未配置的均使用默认值,就是全面放开
<mvc:cors> 
 <mvc:mapping path="/**" /> 
</mvc:cors> 
// 这是一个全量配置
<mvc:cors> 
 <mvc:mapping path="/api/**" 
  allowed-origins="http://domain1.com, http://www.php.cn/" 
  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>
ログイン後にコピー

ee

関連する概念

CorsConfiguration はポジョです特にクロスドメイン構成情報をカプセル化します

  • CorsConfigurationSource リクエストとクロスドメイン構成情報をマッピングするためのコンテナ

  • 特定のクロスドメイン操作用の CorsProcessor クラス

  • Nuogan クロスドメイン構成情報初期化クラス

  • クロスドメイン使用のためのNuoganアダプター

  • 関与するJavaクラス:

情報をカプセル化するpojo

CorsConfiguration

リクエストとクロスドメイン設定情報を保存するコンテナ

CorsConfigurationSource、URLBasedCorsConfigurationSource

特定の処理クラス

CorsProcessor、DefaultCorsProcessor

CorsUtils

OncePerRequestFilterインターフェースを実装

CorsFilter

リクエストがcorsであるかどうかを確認し、対応するアダプター

AbstractHandlerMapping (内部を含む) class PreFlightHandler、CorsInterceptor

CrossOriginアノテーション情報の読み取り

AbstractHandlerMethodMapping、RequestMappingHandlerMapping

xmlファイルからのクロスドメイン構成情報の読み取り

CorsBeanDefinitionParser

クロスドメインの登録補助クラス

MvcNamespaceUtils

debug分析

必要なコードを理解するには、まずクロスドメイン情報をカプセル化する pojo を理解しましょう -- CorsConfiguration

これは、クロスドメインに対応するいくつかのプロパティに加えて、combined、checkOrigin だけです。 、checkHttpMethod、およびcheckHeaders。 属性は複数の値と組み合わせて使用​​されます。

@CrossOrigin(maxAge = 3600) 
@RestController 
@RequestMapping("/account") 
public class AccountController { 
 @CrossOrigin("http://domain2.com") 
 @RequestMapping("/{id}") 
 public Account retrieve(@PathVariable Long id) { 
  // ... 
 } 
}
ログイン後にコピー

combine は、クロスドメイン情報をマージすることです

3 つのチェック方法は、リクエスト内の情報が許可された範囲に含まれているかどうかをチェックすることです

設定の初期化

が、システムが開始され、構成ファイルを解析します。RequestMappingHandlerMapping をロードするときに、InitializingBean の afterProperties フックを通じて initCorsConfiguration を呼び出し、アノテーション情報を初期化します。

構成ファイルの初期化

CorsBeanDefinitionParser クラスの parse メソッドにブレークポイントを置きます。

CorsBeanDefinitionParserのコールスタック

ここでコードを通して解析を確認できます

クロスドメイン情報の構成では、パス単位で複数のマッピング関係を定義できます。

解析中に定義がない場合は、デフォルト設定が使用されます

 // 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;
ログイン後にコピー

解析が完了したら、MvcNamespaceUtils.registerCorsConfiguratoions を通じて登録します

ここでは Spring Bean コンテナ管理の統一プロセスに従います。 BeanDefinition に変換されてインスタンス化されます。

// 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));
  }
  // ...
 }
ログイン後にコピー

アノテーションの初期化

RequestMappingHandlerMappingのinitCorsConfiguration内のCrossOriginアノテーションが付けられたメソッドをスキャンして情報を抽出します。

RequestMappingHandlerMapping_initCorsConfiguration

// 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);
 }
ログイン後にコピー

クロスドメインリクエスト処理

HandlerMapping 検索プロセッサを正常に処理した後、AbstractHandlerMapping.getHandlerでクロスドメインリクエストであるかどうかを確認します。 2回で完了します処理:

事前リクエストの場合は、プロセッサを内部クラス 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替换处理器;如果是普通请求,添加一个拦截器CorsInterceptor。

    PreFlightRequest是CorsProcessor对于HttpRequestHandler的一个适配器。这样HandlerAdapter直接使用HttpRequestHandlerAdapter处理。

    CorsInterceptor 是CorsProcessor对于HnalderInterceptorAdapter的适配器。

     // 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);
     }
    ログイン後にコピー


    以上がSpring MVC cors クロスドメイン実装ソースコードのサンプルコード分析の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

    このウェブサイトの声明
    この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。

    ホットAIツール

    Undresser.AI Undress

    Undresser.AI Undress

    リアルなヌード写真を作成する AI 搭載アプリ

    AI Clothes Remover

    AI Clothes Remover

    写真から衣服を削除するオンライン AI ツール。

    Undress AI Tool

    Undress AI Tool

    脱衣画像を無料で

    Clothoff.io

    Clothoff.io

    AI衣類リムーバー

    AI Hentai Generator

    AI Hentai Generator

    AIヘンタイを無料で生成します。

    ホットツール

    メモ帳++7.3.1

    メモ帳++7.3.1

    使いやすく無料のコードエディター

    SublimeText3 中国語版

    SublimeText3 中国語版

    中国語版、とても使いやすい

    ゼンドスタジオ 13.0.1

    ゼンドスタジオ 13.0.1

    強力な PHP 統合開発環境

    ドリームウィーバー CS6

    ドリームウィーバー CS6

    ビジュアル Web 開発ツール

    SublimeText3 Mac版

    SublimeText3 Mac版

    神レベルのコード編集ソフト(SublimeText3)

    Spring Boot と OpenAI の出会いによる新しいプログラミング パラダイム Spring Boot と OpenAI の出会いによる新しいプログラミング パラダイム Feb 01, 2024 pm 09:18 PM

    2023年、AI技術が注目を集め、プログラミング分野を中心にさまざまな業界に大きな影響を与えています。 AI テクノロジーの重要性に対する人々の認識はますます高まっており、Spring コミュニティも例外ではありません。 GenAI (汎用人工知能) テクノロジーの継続的な進歩に伴い、AI 機能を備えたアプリケーションの作成を簡素化することが重要かつ緊急になっています。このような背景から、AI 機能アプリケーションの開発プロセスを簡素化し、シンプルかつ直観的にし、不必要な複雑さを回避することを目的とした「SpringAI」が登場しました。 「SpringAI」により、開発者はAI機能を搭載したアプリケーションをより簡単に構築でき、使いやすく、操作しやすくなります。

    Spring Boot と Spring AI を使用して生成人工知能アプリケーションを構築する Spring Boot と Spring AI を使用して生成人工知能アプリケーションを構築する Apr 28, 2024 am 11:46 AM

    Spring+AI は業界リーダーとして、強力で柔軟な API と高度な機能を通じてさまざまな業界に最先端のソリューションを提供します。このトピックでは、さまざまな分野での Spring+AI の応用例を詳しく掘り下げ、Spring+AI がどのように特定のニーズを満たし、目標を達成し、これらの教訓をより広範囲のアプリケーションに拡張するかを示します。このトピックが Spring+AI の無限の可能性をより深く理解し、活用するきっかけになれば幸いです。 Spring フレームワークはソフトウェア開発の分野で 20 年以上の歴史があり、Spring Boot 1.0 バージョンがリリースされてから 10 年が経過しました。今、その春に異論を唱える人はいない

    Springプログラマティックトランザクションの実装方法は何ですか? Springプログラマティックトランザクションの実装方法は何ですか? Jan 08, 2024 am 10:23 AM

    Spring プログラムによるトランザクションを実装する方法: 1. TransactionTemplate を使用する; 2. TransactionCallback および TransactionCallbackWithoutResult を使用する; 3. Transactional アノテーションを使用する; 4. TransactionTemplate を @Transactional と組み合わせて使用​​する; 5. トランザクション マネージャーをカスタマイズする。

    PHP MVC アーキテクチャ: 将来に向けた Web アプリケーションの構築 PHP MVC アーキテクチャ: 将来に向けた Web アプリケーションの構築 Mar 03, 2024 am 09:01 AM

    はじめに 今日の急速に進化するデジタル世界では、堅牢かつ柔軟で保守可能な WEB アプリケーションを構築することが重要です。 PHPmvc アーキテクチャは、この目標を達成するための理想的なソリューションを提供します。 MVC (Model-View-Controller) は、アプリケーションのさまざまな側面を独立したコンポーネントに分離する、広く使用されている設計パターンです。 MVC アーキテクチャの基礎 MVC アーキテクチャの核となる原則は、関心事の分離です。 モデル: アプリケーションのデータとビジネス ロジックをカプセル化します。ビュー: データの表示とユーザー インタラクションの処理を担当します。コントローラー: モデルとビュー間の対話を調整し、ユーザーのリクエストとビジネス ロジックを管理します。 PHPMVC アーキテクチャ phpMVC アーキテクチャは従来の MVC パターンに従いますが、言語固有の機能も導入しています。以下はPHPMVCです

    Spring でトランザクション分離レベルを設定する方法 Spring でトランザクション分離レベルを設定する方法 Jan 26, 2024 pm 05:38 PM

    Spring でトランザクション分離レベルを設定する方法: 1. @Transactional アノテーションを使用します; 2. Spring 構成ファイルに設定します; 3. PlatformTransactionManager を使用します; 4. Java 構成クラスに設定します。詳細な導入方法: 1. @Transactional アノテーションを使用し、トランザクション管理が必要なクラスまたはメソッドに @Transactional アノテーションを追加し、属性に分離レベルを設定します。 2. Spring の設定ファイルなどで

    Spring プロジェクトでの JUnit 単体テスト フレームワークの適用 Spring プロジェクトでの JUnit 単体テスト フレームワークの適用 Apr 18, 2024 pm 04:54 PM

    JUnit は Spring プロジェクトで広く使用されている Java 単体テスト フレームワークであり、次の手順で適用できます。 JUnit 依存関係を追加します。 org.junit.jupiterjunit-jupiter5.8.1test テスト ケースを作成します。 @ExtendWith(SpringExtension.class) を使用して拡張機能を有効にします。 @Autowired を使用して Bean を注入し、@BeforeEach と @AfterEach を使用して準備とクリーンアップを行い、テスト メソッドを @Test でマークします。

    Spring アノテーションの公開: 一般的なアノテーションの分析 Spring アノテーションの公開: 一般的なアノテーションの分析 Dec 30, 2023 am 11:28 AM

    Spring は、Java 開発を簡素化し、強化するための多くのアノテーションを提供するオープンソース フレームワークです。この記事では、一般的に使用される Spring アノテーションについて詳しく説明し、具体的なコード例を示します。 @Autowired: Autowired @Autowired アノテーションを使用して、Spring コンテナーに Bean を自動的に接続できます。依存関係が必要な場合に @Autowired アノテーションを使用すると、Spring はコンテナー内で一致する Bean を見つけて自動的に注入します。サンプルコードは次のとおりです。

    Spring Security 権限制御フレームワークの使用ガイド Spring Security 権限制御フレームワークの使用ガイド Feb 18, 2024 pm 05:00 PM

    バックエンド管理システムでは、通常、さまざまなユーザーのインターフェイスへのアクセスを制限するために、アクセス許可制御が必要です。ユーザーに特定の権限がない場合、特定のインターフェイスにアクセスできません。この記事では、waynboot-mall プロジェクトを例として、一般的なバックエンド管理システムがアクセス許可制御フレームワーク SpringSecurity を導入する方法を紹介します。 waynboot-mall プロジェクトアドレス: https://github.com/wayn111/waynboot-mall 1. SpringSecurity とは SpringSecurity は、Spring フレームワークをベースとした、強力かつ柔軟なセキュリティの提供を目的としたオープンソース プロジェクトです。 Java アプリケーションの場合。

    See all articles