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