前后端分离——跨域问题

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、配置跨域配置类

@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

这是有时会出现以下报错:

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

# 另外

在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

然后在Shiro的配置类中添加配置类:

LinkedHashMap<String, Filter> filtersMap = new LinkedHashMap<>();
        // 自定义跨域前后端分离验证过滤器
        filtersMap.put("corsAuthenticationFilter", new CORSAuthenticationFilter());
        shiroFilterFactoryBean.setFilters(filtersMap);
1
2
3
4