简介
这是自己做个人博客所遇到的问题,简单记录一下
情况说明
因为携带了token、和shiro的filter才导致了这个问题
token:因为个人业务需要判断是否携带了token 因为token属于header中自定义属性
会导致方法请求前发送一个option请求 为预请求
shiro:因为filter中会去取cookie,所以也会发送option请求
这就导致了跨域问题
解决方案一
package com.az.blogmanagement.cfg;
import com.alibaba.fastjson.serializer.SerializerFeature;
import com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter;
import com.az.blogmanagement.Interceptor.JsonWebTokenInterceptor;
import org.springframework.boot.autoconfigure.http.HttpMessageConverters;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.boot.web.servlet.ServletComponentScan;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.MediaType;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
import org.springframework.web.filter.CorsFilter;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.List;
@Configuration
@ServletComponentScan // 支持自定义web过滤器和servlet
public class WebConfig implements WebMvcConfigurer {
@Bean
public HttpMessageConverters httpMessageConverters() {
FastJsonHttpMessageConverter fjhmc = new FastJsonHttpMessageConverter();
fjhmc.setCharset(Charset.forName("UTF-8"));
List<MediaType> types = new ArrayList<MediaType>();
types.add(MediaType.APPLICATION_JSON_UTF8);
fjhmc.setSupportedMediaTypes(types);
fjhmc.setFeatures(SerializerFeature.WriteEnumUsingToString, SerializerFeature.WriteMapNullValue,
SerializerFeature.QuoteFieldNames, SerializerFeature.PrettyFormat,
SerializerFeature.WriteDateUseDateFormat, SerializerFeature.WriteNullNumberAsZero,
SerializerFeature.WriteNullStringAsEmpty, SerializerFeature.DisableCircularReferenceDetect);
return new HttpMessageConverters(fjhmc);
}
//配置拦截器
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new JsonWebTokenInterceptor()).addPathPatterns("/api/**").addPathPatterns("/c/**").excludePathPatterns("/images/**",
"/js/**");
}
@Bean
public FilterRegistrationBean corsFilter() {
final UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
final CorsConfiguration config = new CorsConfiguration();
// 允许cookies跨域
config.setAllowCredentials(true);
// #允许向该服务器提交请求的URI,*表示全部允许,在SpringMVC中,如果设成*,会自动转成当前请求头中的Origin
config.addAllowedOrigin("*");
// #允许访问的头信息,*表示全部
config.addAllowedHeader("*");
// 预检请求的缓存时间(秒),即在这个时间段里,对于相同的跨域请求不会再预检了
config.setMaxAge(18000L);
// 允许提交请求的方法,*表示全部允许
config.addAllowedMethod("OPTIONS");
config.addAllowedMethod("HEAD");
config.addAllowedMethod("GET");
config.addAllowedMethod("PUT");
config.addAllowedMethod("POST");
config.addAllowedMethod("DELETE");
config.addAllowedMethod("PATCH");
source.registerCorsConfiguration("/**", config);
FilterRegistrationBean bean = new FilterRegistrationBean(new CorsFilter(source));
// 设置监听器的优先级
bean.setOrder(0);
return bean;
}
}
方案二
package com.az.blogmanagement.cfg;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpStatus;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
import org.springframework.web.filter.CorsFilter;
import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
/**
* @author :Azming
* @date :Created in 2022/8/24 13:09
* @description:
* @modified By:
* @version:
*/
@Configuration
public class CorsConfig implements Filter {
private CorsConfiguration buildConfig() {
CorsConfiguration corsConfiguration = new CorsConfiguration();
// 允许任何头
corsConfiguration.addAllowedHeader("*");
// 允许任何方法(post、get等)
corsConfiguration.addAllowedMethod("*");
//允许cookie
corsConfiguration.setAllowCredentials(true);// 是否支持安全证书(必需参数)
corsConfiguration.setMaxAge(3600L);// 预检请求的有效期,单位为秒。
corsConfiguration.addExposedHeader("set-cookie");
corsConfiguration.addExposedHeader("access-control-allow-headers");
corsConfiguration.addExposedHeader("access-control-allow-methods");
corsConfiguration.addExposedHeader("access-control-allow-origin");
corsConfiguration.addExposedHeader("access-control-max-age");
corsConfiguration.addExposedHeader("X-Frame-Options");
return corsConfiguration;
}
@Bean
public CorsFilter corsFilter() {
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
// 对接口配置跨域设置
source.registerCorsConfiguration("/**", buildConfig());
return new CorsFilter(source);
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) servletRequest;
HttpServletResponse response = (HttpServletResponse) servletResponse;
response.setHeader("Access-control-Allow-Origin", request.getHeader("Origin"));
response.setHeader("Access-Control-Allow-Credentials", "true");
response.setHeader("Access-Control-Allow-Headers", request.getHeader("Access-Control-Request-Headers"));
response.addHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE, PUT");
if ("OPTIONS".equals(request.getMethod())) {
response.setStatus(HttpStatus.NO_CONTENT.value());
return;
} else {
filterChain.doFilter(request, response);
}
}
@Bean
public FilterRegistrationBean replaceTokenFilter(){
FilterRegistrationBean registration = new FilterRegistrationBean();
registration.setDispatcherTypes(DispatcherType.REQUEST);
registration.setFilter( new CorsConfig ());
registration.addUrlPatterns("/*");
registration.setName("crosFilter ");
registration.setOrder(1);
return registration;
}
}
两种方案有啥区别,我也不清楚,只知道两种方案都可以解决这个问题
有大佬知道的话,麻烦评论说明一下