Berbagi teknologi

Integrasikan sa-token, pisahkan penerapan front-end dan back-end, serta konfigurasikan corsFliter untuk mengatasi penyebab sebenarnya dari kegagalan lintas domain.

2024-07-12

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

1. Perkenalan

Silakan simak artikel berikut untuk mengetahui alasannya: Cara yang benar untuk menyelesaikan masalah lintas domain dengan memisahkan front-end dan back-end 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

Meskipun artikel ini menemukan postur yang benar setelah banyak upaya, akar penyebab masalahnya tidak ditemukan. Kemudian setelah beberapa pemikiran dan eksplorasi, saya bertanya-tanya apakah lintas domain ini dapat disimulasikan secara lokal, dan kemudian saya mulai mencarinya Wang, staf front-end proyek, kemudian melakukan simulasi lintas-domain lokal. Dalam proyek tersebut, dia memisahkan front-end dan back-end sa-token sebelumnya untuk memecahkan postur lintas-domain yang benar dan mereproduksi masalahnya. setelah mengomentari SimpleCORSFilter di artikel.

2. Masalah berulang

Konfigurasi lintas domain mvc resmi spring5.2.15.RELEASE adalah sebagai berikut:

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

Ikuti metode resmi yang ditautkan di atas, lalu tambahkan kelas CustomCorsFilter sebagai berikut:

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

Konfigurasi CustomCorsFilter telah diverifikasi valid di proyek yang saya kerjakan. Namun, dalam proyek terbaru, tidak ada gunanya menggunakan konfigurasi kelas CustomCorsFilter ini untuk menyelesaikan masalah lintas domain. Pada artikel di atas tentang cara yang benar untuk menyelesaikan masalah lintas domain dengan memisahkan sa-token front-end dan back-end, verifikasi kelas CustomCorsFilter memang tidak valid. Masalah ini benar-benar membingungkan , (SimpleCORSFilter perlu dikomentari, karena SimpleCORSFilter ini dapat digunakan setelah verifikasi). Setelah menjalankan proyek secara lokal, front end mensimulasikan permintaan lintas domain. Saya meletakkan breakpoint pada kode kelas CorsFilter berikut:

   @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

Letakkan juga breakpoint pada metode 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

Maka screenshot breakpointnya seperti berikut:

Antarmuka login adalah permintaan lintas domain yang kompleks dengan http plus nama domain, dan permintaan pra-deteksi (permintaan OPSI) akan dikirim.

gambar debugging cors 2

Dalam proyek yang terintegrasi dengan sa-token, saya menetapkan breakpoint pada metode doFilterInternal OncePerRequestFilter dan menemukan filter berikut:

gambar debugging cors 2

Dapat dilihat bahwa CustomCorsFilter yang kami sesuaikan di atas dijalankan terlebih dahulu, dan dua filter yang terkait dengan sa-token: saPathCheckFilterForServlet dan SaServletFilter dijalankan kemudian, sehingga dugaan sebelumnya lainnya telah dikonfirmasi dengan baik. Breakpoint mengarah ke metode doFilterInternal dari CorsFilter di bawah :

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

Masalahnya terletak pada kode berikut:

CorsUtils.isPreFlightRequest(request)
  • 1

Baris kode ini mengembalikan nilai true, sehingga kembali. Semua filter berikutnya tidak dijalankan, sehingga permintaan tidak dapat mencapai antarmuka. Browser masih melaporkan masalah lintas domain. , ditemukan bahwa setelah permintaan kompleks mengirimkan permintaan pra-deteksi (permintaan OPTIONS) di seluruh domain, Asal akan disetel dengan cara yang tidak dapat dijelaskan:

http://localhost:3000
  • 1

Ini sangat aneh, jadi saya meminta rekan front-end saya Lao Wangbang untuk memeriksa di mana nilai ini ditetapkan, dan menemukan yang berikut:

gambar debugging cors 3

Ujung depan tidak menyetel Asal, tetapi hanya menyetel parameter berikut:

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

Pada gambar di atas hanya ada satu nilai Referer yang bertepatan dengan nilai Origin. Apakah ini benar-benar hanya kebetulan saja, maka saya membaca artikel berikut ini:

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

Itu memberi saya banyak ide, jadi saya memikirkannya, dan ternyata CustomCorsFilter yang dikonfigurasi di backend efektif. Bisakah saya mengubah kode sumber CorsFilter? front-end Lao Wang. , kedua metode tersebut layak dilakukan, dan salah satu metode tersebut dapat menyelesaikan masalah lintas domain.

3.Solusi

3.1 Metode 1: Ubah kode sumber CorsFilter di backend

Ubah kode sumber CorsFilter di backend

Tambahkan paket org.springframework.web.filter baru di bawah src.main.java di bawah proyek

Kemudian salin kode sumber CorsFilter dan letakkan di bawah paket org.springframework.web.filter yang baru dibuat di atas, lalu Anda dapat memodifikasi kode sumber 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 Metode 2: Nonaktifkan atau hapus kebijakan perujuk browser di bagian depan

Tambahkan kode berikut ke front end: nonaktifkan atau hapus kebijakan perujuk kebijakan perujuk

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

Kode barunya adalah sebagai berikut:

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

gambar debugging cors 4

Kebijakan perujuk browser ini juga untuk alasan keamanan. Browser yang saya gunakan adalah browser Chrome.

4. Ringkasan

Setelah upaya terus-menerus dan meraba-raba, masalah penerapan lintas domain cors terjadi setelah mengintegrasikan sa-token dalam proyek. Secara umum, spesifikasi protokol lintas domain cors tidak mengizinkan operasi ini Pustaka solusi -end tidak mengizinkan operasi permintaan yang tidak mengikuti spesifikasi protokol lintas domain cors, sehingga Anda dapat menggunakan sa-token untuk memisahkan solusi front-end dan back-end ke postur solusi lintas domain yang benar . Konfigurasikan SimpleCORSFilter, tulis parameter tertentu, dan proses Permintaan pra-deteksi mengembalikan kode status 200, atau Anda dapat menggunakan salah satu dari dua metode dalam artikel ini untuk menyelesaikan masalah lintas domain cors Saya men-debugnya setelah mereproduksi permintaan lintas-domain pada titik henti sementara. Solusi, jika Anda yakin dapat mengikuti metode dalam artikel ini, buat ulang permintaan lintas-domain secara lokal dan kemudian debug titik henti tersebut untuk melihat apakah ada masalah dengan itu. baris CorsUtils.isPreFlightRequest(request) dari corsFilter. Secara umum, masalah lintas domain cors ini adalah masalah besar bagi browser. Permintaan sederhana ke corsFilter tidak akan gagal. . Karena kebijakan perujuk kebijakan perujuk browser akan membawa nilai, Setelah pemrosesan back-end, nilai ini akan ditetapkan ke atribut Asal dari header permintaan, menyebabkan baris kode CorsUtils.isPreFlightRequest(request) dari corsFilter mengembalikan nilai true. dan kemudian kembali. Akibatnya, doFilter dari rangkaian Filter berikutnya tidak dijalankan, dan Tidak ada akses ke antarmuka back-end, dan halaman browser front-end masih melaporkan masalah lintas domain , masalah ini sungguh mengganggu. Metode https tidak berfungsi lintas domain, karena https mendengarkan port 443 dan memerlukan sertifikat. Saya kira ini memerlukan konfigurasi sertifikat. Artikel ini menjelaskan tuduhan bahwa mengintegrasikan sa-token akan menyebabkan konfigurasi corsFilter menjadi tidak valid Hal yang sama terjadi di Internet. Tidak ada artikel dalam artikel ini yang memiliki solusi untuk situasi ini. Harus dikatakan bahwa ini adalah yang pertama. Pembuatannya tidak mudah. ​​Harap hargai orisinalitas penulis original Silahkan cetak ulang dan tambahkan sumber aslinya. Sharing ini berakhir disini, semoga sharing saya dapat menginspirasi dan membantu anda. Silahkan klik tiga kali untuk menyambung ya!