2011-08-18 48 views
11

アンドロイドネイティブアプリのhttps接続でクッキーを使用する必要があります。 私はRestTemplateを使用しています。Spring Android:RestTemplateをhttpsとクッキーで使用する

確認する他のスレッド (例えばSetting Security cookie using RestTemplate) 私はhttp接続の中にクッキーを処理することができました:これは、HTTP上ではなく、HTTPSで正常に動作YourClientHttpRequestFactory extends SimpleClientHttpRequestFactory

restTemplate.setRequestFactory(new YourClientHttpRequestFactory()); 

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

のHttpUtilsここで説明されています: http://www.makeurownrules.com/secure-rest-web-service-mobile-application-android.html

私の問題は、私がする必要があるということです

は、一方で私は、SSL証明書を信頼のAndroidのhttpsの問題を整理することができましたClientHttpRequestFactoryの1つの実装を使用します。 だから私は3つのオプションがあります。

1)SimpleClientHttpRequestFactory

2を使用して、HTTPSを処理するための方法を見つける)をHttpComponentsClientHttpRequestFactory

3を使用してクッキーを処理するための方法を見つけるには)私が持っていた別のアプローチ

+1

HttpUtilsリンクありがとうございます! SSLの解決には絶望的でしたが、他のヒントは助けになりませんでした。 – Solata

答えて

8

を使用します同じ問題。私の解決策は次のとおりです。

まず、私はあなたが行ったのと同じ方法でSSLを処理しました(私はBob Leeの方法を使用しました)。

クッキーは別の話です。以前RestTemplateを使わずにCookieを処理したことは、HttpContextのインスタンスをHttpClientのexecuteメソッドに渡すことだけです。つまり、ApacheのHttpClientクラスを直接使用することです。バックステップを見てみましょう...

のHttpClientはそのうちの1つは、オーバーロードexecute方法の数があります。

execute(HttpUriRequest request, HttpContext context) 

の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のインスタンスにクッキーを追加することができます:あなたはのHttpContextのインスタンスを作成すると、は、cookiestore(どちらかが前の要求から保存された新しいもの、または1)を提供もし良かったら。今、あなたはexecuteメソッドを呼び出したとき、のHttpContextのインスタンスを使用します。

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

(httpRequesterはHttpPost、HTTPGETのインスタンスである場合など)

あなたは、後続の要求上の任意のクッキーを再送する必要がある場合は、あなたがどこかにクッキーを保存することを確認してください。

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; 
    } 
} 
} 

BUT !!!! 2012年1月現在Spring上のRestTemplateはリクエストの実行に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を使用してリクエスト/レスポンスヘッダからクッキーを追加/取得する必要がありました。

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; 
} 

} 

intercepterは、要求をインターセプトし、要求に追加するすべてのクッキーがあるかどうかを確認するためにキャッシュを調べ、その要求を実行し、その後、将来の使用のために応答して格納それらをオフに任意のクッキーを引っ張ります。

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

をそしてそこに行く:

要求テンプレートにインターセプタを追加!私はそれを試して、それは動作します。 RestTemplateで直接HttpContextを使うことができるとき、それはSpring Android 1.0.0.RC1まであなたを保持するはずです。

これは他人に役立つことを望みます!

関連する問題