最近有人問我一個問題,現象是他的應用程式呼叫被 Spring Security 保護的服務時,如果未將 csrf disable,系統就無法正常運作。
Spring Security 啟用 CSRF 後可保護 Server Side 的 Resource,避免跨網域攻擊 (從別的機器發出 Request 以取得後端的資訊)。所以,當 Spring Security 啟用 CSRF 後,我們會在前端的頁面加上
<input type="hidden" name="${_csrf.parameterName}" value="${_csrf.token}"/>
以便,證明我們是從同一個網域發送的請求。
然而,這個問題卻不是上述原因造成!第一時間的猜想錯誤,所以我就開始檢視程式碼內容,來看看到底那邊出了問題。
後來,發現在後端的程式中有一段使用 RestTemplate 去呼叫 REST 服務。基本上,如果在內部應該可以直接呼叫相關的物件,而不需要透過 RestTemplate 來進行呼叫 (多繞了一圈)。不過,依照範例來看是個教學程式,所以就先不討論合理性的問題。
RestTemplate 其實是一個增強化的 HTTP Client ,所以在使用 RestTemplate 時我們可以想像自己開了一個新的瀏覽器,然後存取該服務。此時,RestTemplate 中根本就沒有儲存相關的 Session。因為他的 Request 中沒有帶任何經過驗證的資訊。所以,會被 Spring Security 視為不合法的存取。
我們必須在 RestTemplate 中加入一些資訊,才可讓這個呼叫合法。相關資訊, 可參考下列參考資訊的網址。
HttpHeaders headers = new HttpHeaders();
headers.add("cookie", req.getHeader("cookie"));HttpEntity requestEntity = new HttpEntity(null, headers);
ResponseEntity rssResponse =restTemplate.exchange( your_service_url,HttpMethod.GET,requestEntity, List.class);
1. 建立 HttpHeader 物件,並將 request header 中的 cookie 值取出,設定到自己建立的 HttpHeader 中。(因為 Session 就存在這裡)
2. 建立 HttpEntity 物件,並利用先前建立的 HttpHeader 進行初始化。
3. 使用 restTemplate 呼叫後端服務,取得 ResponseEntity 以進行後續邏輯運算
2. 建立 HttpEntity 物件,並利用先前建立的 HttpHeader 進行初始化。
3. 使用 restTemplate 呼叫後端服務,取得 ResponseEntity 以進行後續邏輯運算
[參考資料]
1 則留言:
Casinos in and Near Buffalo - Mapyro
Casinos in and Near Buffalo · 1. Harrah's 속초 출장마사지 Resort And Casino · 2. 동두천 출장샵 Bally's, MI, 2. MGM National Harbor, 3. Caesars 계룡 출장안마 Palace, 4. Tropicana Grande, 5. 대구광역 출장샵 MGM Grand, 6. Hollywood 진주 출장안마
張貼留言