Partage de technologie

Intégrez le jeton sa, séparez le déploiement front-end et back-end et configurez corsFliter pour résoudre la véritable cause de l'échec entre domaines.

2024-07-12

한어Русский языкEnglishFrançaisIndonesianSanskrit日本語DeutschPortuguêsΕλληνικάespañolItalianoSuomalainenLatina

1. Introduction

Veuillez vous référer à l'article suivant pour la raison : La bonne façon de résoudre les problèmes inter-domaines en séparant le front-end et le back-end de sa-token

https://mp.weixin.qq.com/s/96WbWL28T5_-xzyCfJ7Stg
https://blog.csdn.net/qq_34905631/article/details/140233780?spm=1001.2014.3001.5501
  • 1
  • 2

Bien que cet article ait trouvé la bonne posture après de nombreuses tentatives, la cause première du problème n'a pas été trouvée. Puis, après réflexion et exploration, je me suis demandé si ce cross-domaine pouvait être simulé localement, puis j'ai commencé à le chercher. Wang, l'équipe front-end du projet, a ensuite effectivement simulé un cross-domain local dans le projet, il a séparé le front-end et le back-end du jeton sa précédent pour résoudre la posture correcte du cross-domain et reproduire le problème. après avoir commenté SimpleCORSFilter dans l'article.

2. Récurrence du problème

La configuration inter-domaines du mvc officiel spring5.2.15.RELEASE est la suivante :

https://docs.spring.io/spring-framework/docs/5.2.15.RELEASE/spring-framework-reference/web.html#mvc-cors-intro
  • 1

Suivez la méthode officielle liée ci-dessus, puis ajoutez une classe CustomCorsFilter comme suit :

package xxxx.config;

import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.CorsConfigurationSource;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
import org.springframework.web.filter.CorsFilter;


@Component
@Order(Ordered.HIGHEST_PRECEDENCE)
public class CustomCorsFilter extends CorsFilter {

    public CustomCorsFilter() {
        super(corsConfigurationSource());
    }

    private static CorsConfigurationSource corsConfigurationSource() {
        CorsConfiguration configuration = new CorsConfiguration();
        configuration.addAllowedOrigin("*"); // 允许访问的域名,例如 http://localhost:8080
        configuration.addAllowedHeader("*"); // 允许所有请求头
        configuration.addAllowedMethod("*"); // 允许所有请求方法
        configuration.setAllowCredentials(true);
        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        source.registerCorsConfiguration("/**", configuration);
        return source;
    }

}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31

La configuration de CustomCorsFilter a été vérifiée comme étant valide dans un projet sur lequel j'ai travaillé. Cependant, dans un projet récent, il est inutile d'utiliser cette configuration de classe CustomCorsFilter pour résoudre des problèmes inter-domaines. Dans l'article ci-dessus sur la manière correcte de résoudre les problèmes inter-domaines en séparant le front-end et le back-end du jeton sa, la vérification de la classe CustomCorsFilter était en effet invalide. Ce problème était vraiment déroutant lorsque j'ai reconfiguré la classe CustomCorsFilter dans le projet. , (SimpleCORSFilter doit être commenté, car ce SimpleCORSFilter peut être utilisé après vérification). Après avoir exécuté le projet localement, le front-end simule les requêtes inter-domaines dans le code suivant de la classe CorsFilter :

   @Override
	protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response,
			FilterChain filterChain) throws ServletException, IOException {

		CorsConfiguration corsConfiguration = this.configSource.getCorsConfiguration(request);
		boolean isValid = this.processor.processRequest(corsConfiguration, request, response);
        //关键就是这里,在这里打上断点
		if (!isValid || CorsUtils.isPreFlightRequest(request)) {
			return;
		}
		filterChain.doFilter(request, response);
	}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

Mettez également un point d'arrêt sur la méthode CorsUtils.isPreFlightRequest :

	public static boolean isPreFlightRequest(HttpServletRequest request) {
		return (HttpMethod.OPTIONS.matches(request.getMethod()) &&
				request.getHeader(HttpHeaders.ORIGIN) != null &&
				request.getHeader(HttpHeaders.ACCESS_CONTROL_REQUEST_METHOD) != null);
	}
  • 1
  • 2
  • 3
  • 4
  • 5

Ensuite, la capture d'écran du point d'arrêt est la suivante :

L'interface de connexion est une requête inter-domaine complexe avec http plus un nom de domaine, et une requête de pré-détection (demande OPTIONS) sera envoyée.

cors débogage image 2

Dans le projet intégré à sa-token, j'ai défini un point d'arrêt sur la méthode doFilterInternal de OncePerRequestFilter et j'ai trouvé les filtres suivants :

cors débogage image 2

On peut voir que le CustomCorsFilter que nous avons personnalisé ci-dessus est exécuté en premier, et les deux filtres liés au sa-token : saPathCheckFilterForServlet et SaServletFilter sont exécutés plus tard, donc d'autres conjectures précédentes ont été bien confirmées. Le point d'arrêt va à la méthode doFilterInternal de CorsFilter ci-dessous. :

       //关键就是这里,在这里打上断点
		if (!isValid || CorsUtils.isPreFlightRequest(request)) {
			return;
		}
  • 1
  • 2
  • 3
  • 4

Le problème réside dans le code suivant :

CorsUtils.isPreFlightRequest(request)
  • 1

Cette ligne de code a renvoyé true, elle a donc été renvoyée. Tous les filtres suivants n'ont pas été exécutés, la requête n'a donc pas pu atteindre l'interface. Le navigateur signalait toujours des problèmes inter-domaines. Ensuite, j'ai débogué la ligne de code CorsUtils.isPreFlightRequest(request). , il a été constaté qu'après qu'une requête complexe envoyait une requête de pré-détection (requête OPTIONS) entre domaines, l'origine était définie de manière inexplicable :

http://localhost:3000
  • 1

C'était très étrange, j'ai donc demandé à mon collègue front-end Lao Wangbang de vérifier où cette valeur était définie et j'ai trouvé ce qui suit :

cors débogage image 3

Le frontal ne définit pas Origin, mais définit uniquement les paramètres suivants :

//设置axios跨域访问
axios.defaults.withcredentials = true // 设置cross跨域 并设置访问权限 允许跨域携带cookie信息axios.defaults.crossDomain=true //设置axios跨域的配置
  • 1
  • 2

Dans l'image ci-dessus, il n'y a qu'une seule valeur Referer qui coïncide avec la valeur Origin. Est-ce vraiment juste une coïncidence, j'ai donc lu l'article suivant :

https://blog.csdn.net/qq_55316925/article/details/128571809
  • 1

Cela m'a donné beaucoup d'idées, alors j'y ai réfléchi, et il s'est avéré que le CustomCorsFilter configuré sur le backend était efficace. Puis-je changer le code source de CorsFilter ? J'ai donc essayé les deux méthodes suivantes, qui ont été vérifiées par moi et ? le front-end Lao Wang , les deux méthodes sont réalisables, et l'une ou l'autre peut résoudre le problème inter-domaines cors.

3.Solution

3.1 Méthode 1 : Modifier le code source de CorsFilter sur le backend

Modifier le code source de CorsFilter sur le backend

Ajoutez un nouveau package org.springframework.web.filter sous src.main.java sous le projet

Copiez ensuite le code source de CorsFilter et placez-le sous le package org.springframework.web.filter nouvellement créé ci-dessus, puis vous pourrez modifier le code source de CorsFilter.

/*
 * Copyright 2002-2019 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.springframework.web.filter;

import java.io.IOException;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.util.Assert;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.CorsConfigurationSource;
import org.springframework.web.cors.CorsProcessor;
import org.springframework.web.cors.CorsUtils;
import org.springframework.web.cors.DefaultCorsProcessor;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;

/**
 * {@link javax.servlet.Filter} that handles CORS preflight requests and intercepts
 * CORS simple and actual requests thanks to a {@link CorsProcessor} implementation
 * ({@link DefaultCorsProcessor} by default) in order to add the relevant CORS
 * response headers (like {@code Access-Control-Allow-Origin}) using the provided
 * {@link CorsConfigurationSource} (for example an {@link UrlBasedCorsConfigurationSource}
 * instance.
 *
 * <p>This is an alternative to Spring MVC Java config and XML namespace CORS configuration,
 * useful for applications depending only on spring-web (not on spring-webmvc) or for
 * security constraints requiring CORS checks to be performed at {@link javax.servlet.Filter}
 * level.
 *
 * <p>This filter could be used in conjunction with {@link DelegatingFilterProxy} in order
 * to help with its initialization.
 *
 * @author Sebastien Deleuze
 * @since 4.2
 * @see <a href="https://www.w3.org/TR/cors/">CORS W3C recommendation</a>
 */
public class CorsFilter extends OncePerRequestFilter {

	private final CorsConfigurationSource configSource;

	private CorsProcessor processor = new DefaultCorsProcessor();


	/**
	 * Constructor accepting a {@link CorsConfigurationSource} used by the filter
	 * to find the {@link CorsConfiguration} to use for each incoming request.
	 * @see UrlBasedCorsConfigurationSource
	 */
	public CorsFilter(CorsConfigurationSource configSource) {
		Assert.notNull(configSource, "CorsConfigurationSource must not be null");
		this.configSource = configSource;
	}


	/**
	 * Configure a custom {@link CorsProcessor} to use to apply the matched
	 * {@link CorsConfiguration} for a request.
	 * <p>By default {@link DefaultCorsProcessor} is used.
	 */
	public void setCorsProcessor(CorsProcessor processor) {
		Assert.notNull(processor, "CorsProcessor must not be null");
		this.processor = processor;
	}


	@Override
	protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response,
			FilterChain filterChain) throws ServletException, IOException {

		CorsConfiguration corsConfiguration = this.configSource.getCorsConfiguration(request);
		boolean isValid = this.processor.processRequest(corsConfiguration, request, response);
		//修改的源码是将CorsUtils.isPreFlightRequest(request)这行代码移除,就是因为复杂请求跨域发了预检测请求,浏览器的referrer-policy引用者策略会携带一个值,后端处理之后会将这个值赋值给请求头的Orgin属性上,移除这行代码之后就可以正常访问到登录接口了,前端也没有报跨域了。
        if (!isValid) {
			return;
		}
		filterChain.doFilter(request, response);
	}

}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97

3.2 Méthode 2 : désactiver ou supprimer la stratégie de référencement du navigateur sur le front-end

Ajoutez le code suivant au front-end : désactivez ou supprimez la stratégie de référence referrer-policy`

https://blog.csdn.net/qq_49810363/article/details/111036180
  • 1

Le nouveau code est le suivant :

<meta name="referrer" content="never">
  • 1

cors débogage image 4

La politique de référencement du navigateur est également pour des raisons de sécurité. Le navigateur que j'utilise est le navigateur Chrome.

4. Résumé

Après des tentatives et des tâtonnements constants, le problème du déploiement inter-domaines cors est survenu après l'intégration de sa-token dans le projet. De manière générale, les spécifications du protocole inter-domaines cors ne permettent pas cette opération. La bibliothèque de solutions -end n'autorise pas les opérations de requête qui ne suivent pas les spécifications du protocole inter-domaines cors, vous pouvez donc utiliser sa-token pour séparer les solutions front-end et back-end selon la posture correcte des solutions inter-domaines. . Configurez un SimpleCORSFilter, écrivez des paramètres spécifiques et traitez La demande de pré-détection renvoie un code d'état 200, ou vous pouvez utiliser l'une des deux méthodes de cet article pour résoudre le problème inter-domaines cors. Je le débogue après avoir reproduit la requête inter-domaine au point d'arrêt. Solution, si vous pensez pouvoir suivre la méthode de cet article, reproduisez la requête inter-domaine localement puis déboguer le point d'arrêt pour voir s'il s'agit d'un problème avec. la ligne CorsUtils.isPreFlightRequest(request) de corsFilter. En général, ce cors Le problème inter-domaines est un gros problème pour les navigateurs. Une simple requête à corsFilter n'échouera pas. Une requête complexe envoie une requête de pré-détection (requête OPTIONS). Étant donné que la politique de référence de la politique de référence du navigateur portera une valeur, après le traitement back-end, cette valeur sera attribuée à l'attribut Origin de l'en-tête de la requête, provoquant le retour de la ligne de code CorsUtils.isPreFlightRequest(request) de corsFilter. puis revenez. En conséquence, le doFilter de la série de filtres suivante n'est pas exécuté, et il n'y a pas d'accès à l'interface back-end, et la page du navigateur frontal signale toujours des problèmes inter-domaines. , ce problème est vraiment ennuyeux. La méthode https ne fonctionne pas sur plusieurs domaines, car https écoute le port 443 et nécessite un certificat. Je suppose que cela nécessite la configuration du certificat. Cet article clarifie l'accusation selon laquelle l'intégration de sa-token entraînera l'invalidité de la configuration de corsFilter. C'est la même chose sur Internet. Aucun des articles de cet article n'a de solution à cette situation. Il faut dire que c'est la première. Veuillez respecter l'originalité de l'auteur. original. Veuillez réimprimer et ajouter la source originale. Ce partage se termine ici. J'espère que mon partage pourra vous inspirer et vous aider. Veuillez cliquer trois fois pour vous connecter, d'accord !