spring 跨域

WebMvcConfig

这种方法是基于WebMvcConfigurer实现的全局跨域

import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

@Configuration
public class WebMvcConfig implements WebMvcConfigurer {
    //支持全局跨域
    @Override
    public void addCorsMappings(CorsRegistry registry){
        registry.addMapping("/**")
                .allowedOriginPatterns("*") //允许所有源跨域
                .allowCredentials(true)     //是否发送cookie信息
                .allowedMethods("GET", "POST")//放行哪些原始域请求方式
                .allowedHeaders("*")//放行哪些原始域
                .maxAge(3600 * 24);
    }

}

失效情况

  • 如果一个项目中存在多个WebMvcConfigurationSupport或者WebMvcConfigurerAdapter,可能会导致设置的允许跨域addCorsMappings不生效。

  • 使用此方法配置之后再使用自定义拦截器时跨域相关配置就会失效 。

    原因是请求经过的先后顺序问题,当请求到来时会先进入拦截器中,而不是进入Mapping映射中,所以返回的头信息中并没有配置的跨域信息。浏览器就会报跨域异常。

CorsConfig

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
import org.springframework.web.filter.CorsFilter;


@Configuration
public class CorsConfig {
    private CorsConfiguration buildConfig() {
        CorsConfiguration corsConfiguration = new CorsConfiguration();
        corsConfiguration.setAllowCredentials(true);
        corsConfiguration.allowedOriginPatterns("*");
        corsConfiguration.addAllowedHeader("*");
        corsConfiguration.addAllowedMethod("*");
        return corsConfiguration;
    }
    @Bean
    public CorsFilter corsFilter() {
        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        source.registerCorsConfiguration("/**", buildConfig());

        return new CorsFilter(source);
    }
}

@CrossOrigin

注解的方式针对单个请求进行跨域

@CrossOrigin()
@RequestMapping("/demoController")
@Controller
public class DemoController {
	@Autowired
	IDemoService demoService;
 
	@RequestMapping(value = "/test", method = RequestMethod.POST)
	@ResponseBody
	public ResultModel test(HttpServletRequest request)
			throws Exception {
		return “right”;
	}
}

以上所有方式都需要注意跨域的请求,如果有登录拦截,是会出现“同源策略禁止读取”。因为登录拦截一般优先其它拦截器,会到不了后面我们需要处理的跨域授权拦截器

示例

CosFilter不行

springsecurity中配置跨域,除了上面的步骤外,还需要配置

//1.需要在springsecurity配置中加上cors()来开启跨域以及
//requestMatchers(CorsUtils::isPreFlightRequest).permitAll()来处理跨域请求中的preflight请求。


		//开启跨域 cors()
        http.cors().and().csrf().disable().authorizeRequests()
                //处理跨域请求中的Preflight请求
                .requestMatchers(CorsUtils::isPreFlightRequest).permitAll()
                .antMatchers(HttpMethod.GET,"/hello/hello").permitAll()
                .antMatchers("/oauth/login").permitAll()
                .anyRequest().authenticated()
                .and()
                .formLogin()
                //自定义登录页面
                .loginPage("/oauth/login")
                .and()
                .logout()
                .and()
                .addFilter(new JWTLoginFilter(authenticationManager()))
                .addFilter(new JWTAuthenticationFilter(authenticationManager()));

配置了之后登录还是报跨域错误,是因为验证通过返回的请求头缺少了一些 'Access-Control-Allow-Origin',

 @Override
    protected void successfulAuthentication(HttpServletRequest request, HttpServletResponse response, FilterChain chain, Authentication auth) throws IOException, ServletException {
        。。。。。。
        
        //map.put("loginName", user.getUsername());
        response.setHeader("Access-Control-Allow-Origin", request.getHeader("Origin"));
        response.setHeader("Access-Control-Allow-Credentials", "true");
        response.setHeader("Access-Control-Allow-Methods", "POST, PUT, GET, OPTIONS, DELETE");
        response.setHeader("Access-Control-Allow-Headers", "Authorization, Content-Type,X-Requested-With");

        ResponseUtil.out(response, RespBean.ok(map));
        log.info("登录成功");
    }

配置成功后,前端不需要代理或其他方式,就能实现跨域。

但是使用代理实现跨域一直事最优解。

评论

Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×