2011-08-18 82 views
11

我需要在來自android本機應用程序的https連接上使用cookie。 我正在使用RestTemplate。Spring Android:通過https和cookies使用RestTemplate

檢查其他線程 (如:Setting Security cookie using RestTemplate) 我能HTTP連接中處理Cookie:

restTemplate.setRequestFactory(new YourClientHttpRequestFactory()); 

其中YourClientHttpRequestFactory extends SimpleClientHttpRequestFactory

這可以在HTTP,但不是HTTPS罰款。

在另一方面,我能夠理清的Android信任的SSL證書的HTTPS問題:

restTemplate.setRequestFactory(new HttpComponentsClientHttpRequestFactory(HttpUtils.getNewHttpClient())); 

其中HttpUtils這裏描述: http://www.makeurownrules.com/secure-rest-web-service-mobile-application-android.html

我的問題是,我需要使用ClientHttpRequestFactory的單個實現。 所以我有3個選項:

1)找到一種方法來處理HTTPS使用SimpleClientHttpRequestFactory

2)找到一個方法來處理Cookie使用HttpComponentsClientHttpRequestFactory

3)使用其他方法

+1

感謝您的HttpUtils鏈接!絕望的解決SSL和其他提示沒有幫助。 – Solata

回答

8

我一樣的問題。這裏是我的解決方案:

首先,我以和你一樣的方式處理SSL(我使用Bob Lee的方法)。

餅乾是一個不同的故事。過去沒有RestTemplate(即直接使用Apache的HttpClient類)處理Cookie的方式是將HttpContext的實例傳遞給HttpClient的execute方法。讓我們退後一步......

的HttpClient有許多重載execute方法,其中之一是:

execute(HttpUriRequest request, HttpContext context) 

的HttpContext的實例可以有一個的CookieStore的參考。當您創建的HttpContext的實例,提供的CookieStore(無論是從以前的請求保存的一個新的,或一個):

private HttpContext createHttpContext() { 

    CookieStore cookieStore = (CookieStore) StaticCacheHelper.retrieveObjectFromCache(COOKIE_STORE); 
    if (cookieStore == null) { 
     Log.d(getClass().getSimpleName(), "Creating new instance of a CookieStore"); 
     // Create a local instance of cookie store 
     cookieStore = new BasicCookieStore(); 
    } 

    // Create local HTTP context 
    HttpContext localContext = new BasicHttpContext(); 
    // Bind custom cookie store to the local context 
    localContext.setAttribute(ClientContext.COOKIE_STORE, cookieStore); 
    return localContext; 
} 

當然,你也可以發送請求之前添加餅乾的CookieStore實例如果你喜歡。現在,當你調用execute方法,使用的HttpContext的該實例:

HttpResponse response = httpClient.execute(httpRequester, localContext); 

(其中httpRequester是HttpPost,HTTPGET等實例)

如果您需要重新發送在後續請求中的任何cookie,請確保您存儲的cookie的地方:

StaticCacheHelper.storeObjectInCache(COOKIE_STORE, localContext.getAttribute(ClientContext.COOKIE_STORE), MAX_MILLISECONDS_TO_LIVE_IN_CACHE); 

是在這段代碼中使用的StaticCacheHelper類僅僅是可以將數據存儲在自定義類靜態地圖:

public class StaticCacheHelper { 

private static final int TIME_TO_LIVE = 43200000; // 12 hours 

private static Map<String, Element> cacheMap = new HashMap<String, Element>(); 

/** 
* Retrieves an item from the cache. If found, the method compares 
* the object's expiration date to the current time and only returns 
* the object if the expiration date has not passed. 
* 
* @param cacheKey 
* @return 
*/ 
public static Object retrieveObjectFromCache(String cacheKey) { 
    Element e = cacheMap.get(cacheKey); 
    Object o = null; 
    if (e != null) { 
     Date now = new Date(); 
     if (e.getExpirationDate().after(now)) { 
      o = e.getObject(); 
     } else { 
      removeCacheItem(cacheKey); 
     } 
    } 
    return o; 
} 

/** 
* Stores an object in the cache, wrapped by an Element object. 
* The Element object has an expiration date, which will be set to 
* now + this class' TIME_TO_LIVE setting. 
* 
* @param cacheKey 
* @param object 
*/ 
public static void storeObjectInCache(String cacheKey, Object object) { 
    Date expirationDate = new Date(System.currentTimeMillis() + TIME_TO_LIVE); 
    Element e = new Element(object, expirationDate); 
    cacheMap.put(cacheKey, e); 
} 

/** 
* Stores an object in the cache, wrapped by an Element object. 
* The Element object has an expiration date, which will be set to 
* now + the timeToLiveInMilliseconds value that is passed into the method. 
* 
* @param cacheKey 
* @param object 
* @param timeToLiveInMilliseconds 
*/ 
public static void storeObjectInCache(String cacheKey, Object object, int timeToLiveInMilliseconds) { 
    Date expirationDate = new Date(System.currentTimeMillis() + timeToLiveInMilliseconds); 
    Element e = new Element(object, expirationDate); 
    cacheMap.put(cacheKey, e); 
} 

public static void removeCacheItem(String cacheKey) { 
    cacheMap.remove(cacheKey); 
} 

public static void clearCache() { 
    cacheMap.clear(); 
} 

static class Element { 

    private Object object; 
    private Date expirationDate; 

    /** 
    * @param object 
    * @param key 
    * @param expirationDate 
    */ 
    private Element(Object object, Date expirationDate) { 
     super(); 
     this.object = object; 
     this.expirationDate = expirationDate; 
    } 
    /** 
    * @return the object 
    */ 
    public Object getObject() { 
     return object; 
    } 
    /** 
    * @param object the object to set 
    */ 
    public void setObject(Object object) { 
     this.object = object; 
    } 
    /** 
    * @return the expirationDate 
    */ 
    public Date getExpirationDate() { 
     return expirationDate; 
    } 
    /** 
    * @param expirationDate the expirationDate to set 
    */ 
    public void setExpirationDate(Date expirationDate) { 
     this.expirationDate = expirationDate; 
    } 
} 
} 

但!!!!截至01年12月Spring中的RestTemplate Android不允許您添加HttpContext來執行請求!這在Spring Framework 3.1.0.RELEASE中得到修復,修復程序爲scheduled to be migrated into Spring Android 1.0.0.RC1

因此,當我們獲得Spring Android 1.0.0.RC1時,我們應該能夠添加上述示例中描述的上下文。在此之前,我們必須使用ClientHttpRequestInterceptor從請求/響應頭中添加/拉取Cookie。

public class MyClientHttpRequestInterceptor implements 
    ClientHttpRequestInterceptor { 

private static final String SET_COOKIE = "set-cookie"; 
private static final String COOKIE = "cookie"; 
private static final String COOKIE_STORE = "cookieStore"; 

/* (non-Javadoc) 
* @see org.springframework.http.client.ClientHttpRequestInterceptor#intercept(org.springframework.http.HttpRequest, byte[], org.springframework.http.client.ClientHttpRequestExecution) 
*/ 
@Override 
public ClientHttpResponse intercept(HttpRequest request, byte[] byteArray, 
     ClientHttpRequestExecution execution) throws IOException { 

    Log.d(getClass().getSimpleName(), ">>> entering intercept"); 
    List<String> cookies = request.getHeaders().get(COOKIE); 
    // if the header doesn't exist, add any existing, saved cookies 
    if (cookies == null) { 
     List<String> cookieStore = (List<String>) StaticCacheHelper.retrieveObjectFromCache(COOKIE_STORE); 
     // if we have stored cookies, add them to the headers 
     if (cookieStore != null) { 
      for (String cookie : cookieStore) { 
       request.getHeaders().add(COOKIE, cookie); 
      } 
     } 
    } 
    // execute the request 
    ClientHttpResponse response = execution.execute(request, byteArray); 
    // pull any cookies off and store them 
    cookies = response.getHeaders().get(SET_COOKIE); 
    if (cookies != null) { 
     for (String cookie : cookies) { 
      Log.d(getClass().getSimpleName(), ">>> response cookie = " + cookie); 
     } 
     StaticCacheHelper.storeObjectInCache(COOKIE_STORE, cookies); 
    } 
    Log.d(getClass().getSimpleName(), ">>> leaving intercept"); 
    return response; 
} 

} 

的截擊機攔截請求,看在高速緩存,看看是否有任何cookie添加到請求,然後執行請求,然後再換任何cookie關閉的響應,並將其存儲以備將來使用。

攔截器添加到請求模板:

restTemplate.setRequestFactory(new HttpComponentsClientHttpRequestFactory(HttpClientHelper.createDefaultHttpClient(GET_SERVICE_URL))); 
ClientHttpRequestInterceptor[] interceptors = {new MyClientHttpRequestInterceptor()}; 
restTemplate.setInterceptors(interceptors); 

而且你去那裏!我已經測試過它,它的工作原理。這應該讓你一直持續到Spring Android 1.0.0.RC1,直到我們可以直接使用HttpContext和RestTemplate。

希望這可以幫助別人!