通過Filter解決跨域問題,可以跨多個域,域可以通過@Value註解取
跨域中不同的域指的是“協議+IP+埠”,只要其中一個不相同就要跨域訪問,為了安全,瀏覽器對於跨域預設是禁止訪問的。現在很多應用的客戶端和服務端是分開的,那麼如何來讓處於不同域的客戶端和服務端實現跨域訪問呢,而且客戶端還可能不止一個,那麼又如何實現多客戶端跨域訪問一個服務端呢?
本文的專案預設使用Maven構建,並使用Spring Security實現安全,首先在src/main/resources目錄建properties檔案,在配置檔案中輸入Access-Control-Allow-Origin=http://192.168.1.1,http://192.168.1.2,http://192.168.1.3,代表客戶端的三個域。(站點必須帶"http://"還有埠號,這裡使用預設埠號80,因此可以省略)
1、通過@Value註解從properties檔案取字串陣列
建一個類,並使用@Component註解標註類,屬性適用@Value註解,注意引用org.springframework.beans包。@Component
public class MyFilter {
@Value("${Access-Control-Allow-Origin:}")// 這裡的冒號加與不加感覺沒區別
String[] originProperties; // 這裡竟然可以直接以陣列接收以逗號分隔的多個屬性
}
這樣就可以直接得到客戶端來源域的陣列。
有的時候@Value取不到值,問題大概有幾個:
1. resources下有很多xml檔案
2. 屬性以com.開頭
3. 如果 resources下同時存在 application.yml,這個檔案裡也必須要有這個屬性
4. 屬性不能是static
2、通過Filter設定響應頭的"Access-Control-Allow-Origin"
"Access-Control-Allow-Origin"是響應頭的信任站點,只可以設定一個站點。讓剛建的類繼承javax.servlet.Filter,重寫doFilter方法,把所有請求的HttpServletResponse的Header的"Access-Control-Allow-Origin"設定信任站點。注意引用javax.servlet包。
httpServletResponse.setHeader("Access-Control-Allow-Origin", "http://192.168.1.72");
當然,通過這種方式只能實現跨一個域。
3、 跨多個域
"Origin"屬性表示請求頭的請求來源,通過第1步的方法已經從properties取多個域名的陣列,通過下邊這句程式碼來取得訪問來源,判斷該訪問來源是否在域名陣列中。
<pre name="code" class="java"><span style="white-space:pre"> </span>// 解決跨域問題,把幾個客戶端來源新增信任
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
HttpServletRequest httpRequest = (HttpServletRequest) request;
HttpServletResponse httpResponse = (HttpServletResponse) response;
String curOrigin = httpRequest.getHeader("Origin");
System.out.println("當前訪問來源是:"+curOrigin);
// 如果當前訪問來源在application.properties的Access-Control-Allow-Origin配置範圍內,則允許訪問,否則不允許
if(curOrigin != null) {
for (int i = 0; i < originProperties.length; i++) {
//System.out.println("允許跨域訪問的來源是:"+originProperties[i]);
if(curOrigin.equals(originProperties[i])) {
httpResponse.setHeader("Access-Control-Allow-Origin", curOrigin);
}
}
} else { // 對於無來源的請求(比如在瀏覽器位址列直接輸入請求的),那就只允許我們自己的機器可以吧
httpResponse.setHeader("Access-Control-Allow-Origin", "http://127.0.0.1");
}
httpResponse.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE, PUT,HEAD");
// 請求來自哪個域,我就允許哪個域的來源,也就是說允許所有域訪問服務,這也太不安全了
//if(httpRequest.getHeader("Origin") != null){
// httpResponse.setHeader("Access-Control-Allow-Origin", curOrigin);
//}
// 這句千萬別忘,讓Filter按預設方式處理請求和響應,如果沒寫,那麼response裡沒有body
chain.doFilter(request, response);
}
這樣就會根據使用者的來源來設定允許跨域的來源:"Access-Control-Allow-Origin"。
4. 跨域中的安全
如果你使用Spring Security,它是通過過濾器鏈來實現安全的,它的過濾器預設優先順序最高,會第一個攔截請求。因此要把我們自己的跨域的Filter設定成優先順序最高:
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
MyFilter myFilter;
protected void configure(HttpSecurity http) throws Exception {
//Spring Security的filter預設再整個filter chain的最前邊,因此需要把我們自己寫的跨域的filter放在最前邊
http.addFilterBefore(myFilter, ChannelProcessingFilter.class)
.authorizeRequests()
.anyRequest().authenticated();
}
}
本文不是重點講Spring Security,因此只是寫了簡單的例子。通過這種方式,而不使用JSONP,我們就可以實現跨多個域了。