SpringSecurity(十九):跨域


跨域是实际应用开发中一个非常常见的需求,在Spring 框架中对于跨域问题的处理方案有好几种,引入了Spring Security之后,跨域问题的处理方案又增加了。

CORS

CORS就是由W3C制定的一种跨域资源共享技术标准,其目的就是为了解决前端的跨域请求。在JavaEE开发中,最常见的前端跨域请求解决方案是JSONP,但是JSONP只支持GET请求,这是一个很大的缺陷,而CORS支持多种HTTP请求方法,也是目前主流的跨域解决方案

CORS中新增了一组HTTP请求字段,通过这些字段,服务器告诉浏览器,哪些网站通过浏览器有权限访问哪些资源,同时规定,对哪些可能修改服务器数据的HTTP请求方法(如GET以外的HTTP请求),浏览器必须首先使用OPTIONS方法发起一个预检请求(preflightrequest),预检请求的目的是查看服务端是否支持即将发起的跨域请求,如果服务端允许,才能发起实际的HTTP请求。在预检请求的返回中,服务器端也可以通知客户端,是否需要携带身份凭证(如Cookie,HTTP认证信息等)

Spring处理方案

Spring中关于跨域的处理一共有三种

@CrossOrigin

Spring中第一种跨域的方式是通过@CrossOrign注解来标记支持跨域,该注解可以添加在方法上,也可以添加在Controller上,当添加在Controller上时,表示Controller中所有接口都支持跨域
例:

@RestController
public class HelloController{
@CrossOrign(orign="http://localhost:8081")
@PostMapping("/post")
public String post(){
return "hello post";
}
}

@CrossOrign注解各属性含义如下:
allowCredentials:浏览器是否应当发送凭证信息,如Cookie等
allowedHeaders:请求被允许的请求头字段,表示所有字段
exposedHeaders:哪些相应头可以作为相应的一部分暴露出来,注意,这里只能一一列举,通配符
无效
maxAge:预检请求的有效期,有效期内不必再次发送预检请求,默认位1800秒
methods:允许的请求方法,表示允许所有方法
origins:允许的域,
表示允许所有的域

addCoresMappings

@CrossOrigin注解需要添加在不同的Controller上,所以还有一种全局的配置方法。就是重写WebMvcConfigurerComposite的addCoresMappings方法

@Configuration
public class WebMvcConfig implements WebMvcConfigurer {

    @Override
    public void addCorsMappings(CorsRegistry registry) {
        registry.addMapping("/**")
                .allowCredentials(false)
                .allowedMethods("*")
                .allowedOrigins("*")
                .exposedHeaders("")
                .allowedHeaders("*")
                .maxAge(3600);
    }
}

addMapping表示要处理的请求地址,接下来的方法含义和@CrossOrigin注解中属性的含义都一一对应,这里不再赘述。

CorsFilter

Spring Security处理方案

当我们为项目添加Spring Security依赖后,发现上面三种跨域方式失效了!

原因很简单。我们的预检请求由于不携带认证信息,所以被Spring Security 过滤器拦截了!

第一种方案

我们仍使用Spring的Cors方法,只需要对预检请求放行即可!

@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests()
                 //注意顺序!
                .requestMatchers(CorsUtils::isPreFlightRequest).permitAll() 
                .anyRequest().authenticated()
                .and()
                .formLogin()
    }
}

第二种方案

我们使用Spring Security的Cors方案

@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
    @Autowired
    FindByIndexNameSessionRepository sessionRepository;
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests()
                .anyRequest().authenticated()
                .and()
                .formLogin()
                .and()
                .cors()
                .configurationSource(corsConfigurationSource())
                .and()
                //关掉csrf防御,方便测试!
                .csrf().disable();

    }
    @Bean
    CorsConfigurationSource corsConfigurationSource(){
        CorsConfiguration corsConfiguration=new CorsConfiguration();
        corsConfiguration.setAllowedHeaders(Arrays.asList("*"));
        corsConfiguration.setAllowedMethods(Arrays.asList("*"));
        corsConfiguration.setAllowedOrigins(Arrays.asList("http://localhost:8081"));
        corsConfiguration.setMaxAge(3600L);
        UrlBasedCorsConfigurationSource source=new UrlBasedCorsConfigurationSource();
        //所有的请求都允许跨域
        source.registerCorsConfiguration("/**",corsConfiguration);
        return  source;
        

    }

}

首先需要提供一个CoresConfigurationSource实例,将跨域的各项配置都填充进去,然后在configure(HttpSecurity)方法中,通过cors()开启跨域配置,并将一开始配置好的CoresConfigurationSource实例设置进去。

cors()方法的实质就是获取一个CorsFilter 并添加在Spring Security过滤器链中(位置在HeaderWriterFilter之后,CsrfFilter之前),此时还没有到认证过滤器。


免责声明!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系本站邮箱yoyou2525@163.com删除。



 
粤ICP备18138465号  © 2018-2025 CODEPRJ.COM