星期一, 8月 08, 2016

RestTemplate 無法呼叫 Rest Service

最近有人問我一個問題,現象是他的應用程式呼叫被 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 以進行後續邏輯運算


[參考資料]

1 則留言:

kalonyahner 提到...

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 진주 출장안마