zuul+security跨域Cors問題解決
簡介
場景
在服務后台都會出現跨域cors問題,不過一般spring解決起來比較方便,在框架+框架的基礎上,問題就顯得特別明顯了,各種沖突,不了解源碼的運行原理,解決起來也是有心無力。
這里介紹的是zuul配置了跨域,在前端調用仍然會出現跨域的問題。
一般沒有權限的接口加上cors配置就會通過跨域的問題。不過在服務間調用具有權限的功能,莫名的報跨域問題。
post特殊請求
在解決問題時發現 post
請求也有點特殊,這里也需要處理一下。
post請求分為簡單請求和復雜請求。
在 CORS
中,可以使用 OPTIONS
方法發起一個預檢請求,以檢測實際請求是否可以被服務器所接受。預檢請求報文中的 Access-Control-Request-Method
首部字段告知服務器實際請求所使用的 HTTP
方法;Access-Control-Request-Headers
首部字段告知服務器實際請求所攜帶的自定義首部字段。服務器基於從預檢請求獲得的信息來判斷,是否接受接下來的實際請求。
以及 OPTIONS
未攜帶任何權限相關的內容,會被認證攔截,我們也得放開 OPTIONS
類型請求
功能使用
Cross 解決
之前設置很簡單,習慣操作把之前的代碼復制了過來,第一次操作是創建了一個 CorsFilter
bean,但是簡單的請求確實通過了,不過權限接口過不了,於是按照一些資料配置了下面的代碼 注入了 FilterRegistrationBean
bean 還設置了 order 加載順序。
解決后無果 仍然和之前的效果一致。
/**
* 跨域配置 C - Cross O - Origin R - Resource S - Sharing
*
* @author purgeyao
* @since 1.0
*/
@Configuration
//@Order(Ordered.HIGHEST_PRECEDENCE)
public class CorsConfig {
@Bean
public FilterRegistrationBean filterRegistrationBean() {
final UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
final CorsConfiguration config = new CorsConfiguration();
config.setAllowCredentials(true);
config.setAllowedOrigins(Arrays.asList("*"));
config.setAllowedHeaders(Arrays.asList("*"));
config.setAllowedMethods(Arrays.asList("*"));
config.setMaxAge(300L);
source.registerCorsConfiguration("/**", config);
CorsFilter corsFilter = new CorsFilter(source);
FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean(corsFilter);
filterRegistrationBean.setOrder(0);
return filterRegistrationBean;
}
}
在一些資料+源碼的幫助下,嘗試了下面代碼:
這次實現了 CorsFilter
類 加載了 @Order
順序為 (Ordered.HIGHEST_PRECEDENCE)
最優先。
/**
* 解決 zuul+oauth2 跨域配置 C - Cross O - Origin R - Resource S - Sharing
*
* @author purgeyao
* @since 1.0
*/
@Component
@Order(Ordered.HIGHEST_PRECEDENCE)
public class AjaxCorsFilter extends CorsFilter {
public AjaxCorsFilter() {
super(configurationSource());
}
private static UrlBasedCorsConfigurationSource configurationSource() {
CorsConfiguration corsConfig = new CorsConfiguration();
// List<String> allowedHeaders = Arrays.asList("x-auth-token", "content-type", "X-Requested-With", "XMLHttpRequest");
List<String> exposedHeaders = Arrays
.asList("x-auth-token", "content-type", "X-Requested-With", "XMLHttpRequest");
// List<String> allowedMethods = Arrays.asList("POST", "GET", "DELETE", "PUT", "OPTIONS");
List<String> allowedHeaders = Arrays.asList("*");
List<String> allowedMethods = Arrays.asList("*");
List<String> allowedOrigins = Arrays.asList("*");
corsConfig.setAllowedHeaders(allowedHeaders);
corsConfig.setAllowedMethods(allowedMethods);
corsConfig.setAllowedOrigins(allowedOrigins);
corsConfig.setExposedHeaders(exposedHeaders);
corsConfig.setMaxAge(36000L);
corsConfig.setAllowCredentials(true);
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", corsConfig);
return source;
}
}
哈哈哈,解決了,但是有沒有感覺到莫名其妙啊,經過了解
發現其實只是一個加載順序的問題,我們上面注入的 FilterRegistrationBean
也可以使用的,只是在設置order的時候有點問題 需要設置比 security
優先級高,改為 Ordered.HIGHEST_PRECEDENCE
發現成功可以通過跨域了。
/**
* 跨域配置 C - Cross O - Origin R - Resource S - Sharing
*
* @author purgeyao
* @since 1.0
*/
@Configuration
//@Order(Ordered.HIGHEST_PRECEDENCE)
public class CorsConfig {
@Bean
public FilterRegistrationBean filterRegistrationBean() {
final UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
final CorsConfiguration config = new CorsConfiguration();
config.setAllowCredentials(true);
config.setAllowedOrigins(Arrays.asList("*"));
config.setAllowedHeaders(Arrays.asList("*"));
config.setAllowedMethods(Arrays.asList("*"));
config.setMaxAge(300L);
source.registerCorsConfiguration("/**", config);
CorsFilter corsFilter = new CorsFilter(source);
FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean(corsFilter);
// 設置為 Ordered.HIGHEST_PRECEDENCE
filterRegistrationBean.setOrder(Ordered.HIGHEST_PRECEDENCE);
return filterRegistrationBean;
}
}
解決解決。。。
OPTIONS請求解決
有關 OPTIONS(NDN
web docs) 介紹。
在發送 post 請求 會發現在真正發送之前會有一個 OPTIONS
請求。
因 OPTIONS
為攜帶任何有狀態的認證信息,被權限攔截下來異常,就沒有之后的真正請求了。
我們只需要吧 OPTIONS
請求放開 返回200狀態即可。
有很多辦法做到,可以在zuul網關放過,也可以通過 security
添加 忽略攔截列表。
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
...
@Override
protected void configure(HttpSecurity http) throws Exception {
...
// 添加忽略攔截OPTIONS 類型的請求
http.authorizeRequests().antMatchers(HttpMethod.OPTIONS).permitAll();
...
}
}
萬事大吉。
總結
簡單的bug解決起來簡單點,不過遇到交集的bug,有心無力的感覺,莫名其妙的問題,需要耐心觀察源碼運行原理。
示例代碼地址:zuul-security
作者GitHub:
Purgeyao 歡迎關注
qq交流群:
812321371
微信交流群:MercyYao
微信公眾號: