前后端分离——跨域问题
早睡蛋 8/2/2022  跨域前后端分离SpringBoot
# 问题概述
通常在使用SpringBoot与Vue等前后端中,会出现跨域的问题。
总结了以下情况的问题:
- 有没开启相关注解
 - 没有配置相关跨域配置类
 - 配置了跨域配置但是仍然报错
 - .....
 
# 解决方案
1、最基本的就是在控制层上加上@CrossOrigin注解,@CrossOrigin注解里面定义了基本的跨域网关参数。
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface CrossOrigin {
	/** @deprecated as of Spring 5.0, in favor of {@link CorsConfiguration#applyPermitDefaultValues} */
	@Deprecated
	String[] DEFAULT_ORIGINS = {"*"};
	/** @deprecated as of Spring 5.0, in favor of {@link CorsConfiguration#applyPermitDefaultValues} */
	@Deprecated
	String[] DEFAULT_ALLOWED_HEADERS = {"*"};
	/** @deprecated as of Spring 5.0, in favor of {@link CorsConfiguration#applyPermitDefaultValues} */
	@Deprecated
	boolean DEFAULT_ALLOW_CREDENTIALS = false;
	/** @deprecated as of Spring 5.0, in favor of {@link CorsConfiguration#applyPermitDefaultValues} */
	@Deprecated
	long DEFAULT_MAX_AGE = 1800;
 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
2、配置跨域配置类
@Configuration
public class CorsConfig extends WebMvcConfigurerAdapter {
    @Override
    public void addCorsMappings(CorsRegistry registry) {
        registry.addMapping("/**")
                .allowedOrigins("*")
                .allowedMethods("*")
                .allowCredentials(true);
    }
}
 1
2
3
4
5
6
7
8
9
10
11
2
3
4
5
6
7
8
9
10
11
这是有时会出现以下报错:
When allowCredentials is true, allowedOrigins cannot contain the special value "*" since that cannot be set on the "Access-Control-Allow-Origin" response header. To allow credentials to a set of origins, list them explicitly or consider using "allowedOriginPatterns" instead.
 1
这是由于SpringBoot中版本升级了导致不一致的原因,按照提示修改如下即可:
allowedOriginPatterns("*")
 1
3、经过上述的方案,基本能解决大部分问题,如果还是报错,则修改配置类,如下:
@Configuration
public class CorsConfig extends WebMvcConfigurerAdapter {
	private CorsConfiguration buildConfig() {
        CorsConfiguration corsConfiguration = new CorsConfiguration();
        corsConfiguration.addAllowedOriginPattern("*");
        corsConfiguration.addAllowedHeader("*");
        corsConfiguration.addAllowedMethod("*");
        corsConfiguration.setMaxAge(3600L);         // 预检请求的有效期,单位为秒。
        corsConfiguration.setAllowCredentials(true);// 是否支持安全证书(必需参数)
        return corsConfiguration;
    }
    @Bean
    public CorsFilter corsFilter() {
        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        source.registerCorsConfiguration("/**", buildConfig());
        return new CorsFilter(source);
    }
    
}
 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# 另外
在Shiro中如果遇到跨域问题,并且是OPTIONS请求的问题,那么编写配置类,对OPTIONS的请求进行放行即可:
public class CORSAuthenticationFilter extends FormAuthenticationFilter {
    // 直接过滤可以访问的请求类型
    private static final String REQUET_TYPE = "OPTIONS";
    public CORSAuthenticationFilter() {
        super();
    }
    @Override
    public boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue) {
        if (((HttpServletRequest) request).getMethod().toUpperCase().equals(REQUET_TYPE)) {
            return true;
        }
        return super.isAccessAllowed(request, response, mappedValue);
    }
    @Override
    protected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws Exception {
        HttpServletResponse res = (HttpServletResponse)response;
        res.setHeader("Access-Control-Allow-Origin", "*");
        res.setStatus(HttpServletResponse.SC_OK);
        res.setCharacterEncoding("UTF-8");
        PrintWriter writer = res.getWriter();
        writer.write(JSONObject.toJSONString(LoginEnums.NO_LOGIN.getResultResponseVo()));
        writer.close();
        return false;
    }
}
 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
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
然后在Shiro的配置类中添加配置类:
LinkedHashMap<String, Filter> filtersMap = new LinkedHashMap<>();
        // 自定义跨域前后端分离验证过滤器
        filtersMap.put("corsAuthenticationFilter", new CORSAuthenticationFilter());
        shiroFilterFactoryBean.setFilters(filtersMap);
 1
2
3
4
2
3
4