2024-07-12
한어Русский языкEnglishFrançaisIndonesianSanskrit日本語DeutschPortuguêsΕλληνικάespañolItalianoSuomalainenLatina
For the reason, please refer to the following article: The correct approach to cross-domain solution of sa-token front-end and back-end separation
https://mp.weixin.qq.com/s/96WbWL28T5_-xzyCfJ7Stg
https://blog.csdn.net/qq_34905631/article/details/140233780?spm=1001.2014.3001.5501
Although this article found the correct approach after many attempts, the root cause of the problem was not found. Then, after some thinking and exploration, I wondered if this cross-domain could be simulated locally. Then I went to find Lao Wang, the front-end person of the project, and then I did simulate the local cross-domain. In the project, I separated the front-end and back-end of sa-token to solve the problem of cross-domain. The problem was reproduced after commenting on SimpleCORSFilter in the article.
The cross-domain configuration of spring5.2.15.RELEASE official mvc is as follows:
https://docs.spring.io/spring-framework/docs/5.2.15.RELEASE/spring-framework-reference/web.html#mvc-cors-intro
According to the official method linked above, a new CustomCorsFilter class is added as follows:
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;
}
}
The configuration of CustomCorsFilter is valid in a project I worked on, but it doesn't work in a recent project. Is this configuration invalid? In the above article, the correct way to solve the cross-domain problem of sa-token front-end and back-end separation, the CustomCorsFilter class verification is indeed invalid. This problem is really puzzling. After I reconfigured the CustomCorsFilter class in the project (SimpleCORSFilter needs to be commented because this SimpleCORSFilter can work after verification), and then ran the project locally, the front-end simulated a cross-domain request, and I set a breakpoint in the following code of the CorsFilter class:
@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);
}
Also put a breakpoint on the CorsUtils.isPreFlightRequest method:
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);
}
Then the breakpoint screenshot is as follows:
The login interface is a complex cross-domain request with http plus domain name, which will send a pre-detection request (OPTIONS request)
In the project that integrates sa-token, breakpoint the doFilterInternal method of OncePerRequestFilter and find the following filters:
It can be seen that the CustomCorsFilter we defined above is executed first, and the two sa-token related filters: saPathCheckFilterForServlet and SaServletFilter are executed later, so the other previous guesses have been well confirmed. When the breakpoint goes to the doFilterInternal method of CorsFilter below:
//关键就是这里,在这里打上断点
if (!isValid || CorsUtils.isPreFlightRequest(request)) {
return;
}
The problem lies in the following code:
CorsUtils.isPreFlightRequest(request)
This line of code returns true, and then returns. All the subsequent filters are not executed, so the request cannot reach the interface, and the browser still reports the cross-domain problem. Then I debugged the CorsUtils.isPreFlightRequest(request) line of code and found that after the complex request sent a pre-detection request (OPTIONS request) across domains, the Origin will be set with an inexplicable:
http://localhost:3000
This is very strange, so I asked my front-end colleague Lao Wang to help me check where this value is set, and then found the following:
The front end does not set Orgin, but only sets the following parameters:
//设置axios跨域访问
axios.defaults.withcredentials = true // 设置cross跨域 并设置访问权限 允许跨域携带cookie信息axios.defaults.crossDomain=true //设置axios跨域的配置
In the above picture, only one Referer value coincides with the Origin value. Is this really just a coincidence? So I read the following article:
https://blog.csdn.net/qq_55316925/article/details/128571809
It gave me a lot of ideas, and then I thought about it, it turned out that the CustomCorsFilter configured in the backend was effective, so can I change the CorsFilter source code? So I tried the following two methods. After verification by me and the front-end Lao Wang, these two methods are feasible, and any one of them can solve the cors cross-domain problem.
Backend modification of CorsFilter source code
Add a package org.springframework.web.filter under src.main.java in the project
Then copy the source code of CorsFilter and put it in the newly created org.springframework.web.filter package above, and you can modify the source code of 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);
}
}
Add the following code to the front end: Disable or remove the referrer-policy` referrer policy
https://blog.csdn.net/qq_49810363/article/details/111036180
The new code is as follows:
<meta name="referrer" content="never">
The browser's referrer-policy is also for security reasons. The browser I use is Chrome.
After continuous attempts and explorations, the problem of cors cross-domain deployment after integrating sa-token in the project is that the specifications of the cors cross-domain protocol do not allow this operation. In addition, the browser and back-end solution libraries do not allow request operations that do not follow the specifications of the cors cross-domain protocol. Therefore, you can use the method in the article "The Correct Posture to Solve Cross-Domain Problems with sa-token" to separate the front and back ends, configure a SimpleCORSFilter, write specific parameters, process the pre-detection request and return a 200 status code, or use either of the two methods in this article to solve the cors cross-domain problem. The solution in this article is the solution I debugged after personally breaking the point to reproduce the cross-domain request. If you believe that you can follow the method in this article, reproduce the cross-domain request locally and then break the point with dubug to see if it is the CorsU of corsFilter. The problem with the line of code tils.isPreFlightRequest(request). Generally speaking, the cross-domain problem of cors is a big blame for the browser. The corsFilter will not fail for simple requests. The complex request sends a pre-detection request (OPTIONS request). Since the browser's referrer-policy policy carries a value, the backend will assign this value to the Orgin property of the request header after processing. As a result, the line of code CorsUtils.isPreFlightRequest(request) of corsFilter returns true and then returns. As a result, the doFilter of the subsequent series of Filters is not executed, and the backend interface is not accessed, while the front-end browser page is still reporting the cross-domain problem. To be honest, this problem is really a pitfall. The cross-domain method of https is not possible, because https listens to port 443 and requires a certificate. I guess this requires configuring a certificate. This article clears the accusation that integrating sa-token will cause the corsFilter configuration to become invalid. There are thousands of similar articles on the Internet that do not have the solution to this situation in this article. It should be said that this is the first of its kind. Creation is not easy. Please respect the author's originality. Please do not plagiarize as the original. Please reprint and add the original source. This sharing ends here. I hope my sharing will inspire and help you. Please click three times in one click. Muah!