2011-08-18 11 views
11

Potrzebuję plików cookie na połączenie https z Android rodzimej aplikacji. Używam RestTemplate.Wiosna Android: używanie RestTemplate z https i ciasteczkami

Sprawdzanie innych wątków (. Np Setting Security cookie using RestTemplate) byłem w stanie obsługiwać pliki cookie w ciągu połączenia http:

restTemplate.setRequestFactory(new YourClientHttpRequestFactory()); 

gdzie YourClientHttpRequestFactory extends SimpleClientHttpRequestFactory

to działa prawidłowo na http, ale nie na https.

Z drugiej strony udało mi się rozwiązać ten problem https Androida ufając certyfikat SSL:

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

gdzie HttpUtils jest opisana tutaj: http://www.makeurownrules.com/secure-rest-web-service-mobile-application-android.html

Moim problemem jest to, że muszę użyj pojedynczej implementacji ClientHttpRequestFactory. Więc mam 3 opcje:

1) znaleźć sposób, aby obsłużyć https korzystając SimpleClientHttpRequestFactory

2) znaleźć sposób, aby obsługiwać ciasteczka korzystając HttpComponentsClientHttpRequestFactory

3) użyć innego podejścia

+1

Dzięki za link HttpUtils! Desperacko szukał rozwiązania na SSL i inne wskazówki nie pomogły. – Solata

Odpowiedz

8

miałem ten sam problem. Oto moje rozwiązanie:

Po pierwsze, obsługiwałem protokół SSL w taki sam sposób, jak to zrobiłem (użyłem metody Boba Lee).

Pliki cookie to inna historia. Sposób w jaki obsługiwałam ciasteczka w przeszłości bez RestTemplate (to znaczy po prostu używając klasy HttpClient Apache'a bezpośrednio) to przekazanie instancji HttpContext do metody execute HttpClienta. Weźmy krok wstecz ...

HttpClient posiada szereg metod przeciążonych execute, z których jeden jest:

execute(HttpUriRequest request, HttpContext context) 

Wystąpienie HttpContext może mieć odniesienie do CookieStore. Podczas tworzenia instancji HTTPContext, zapewniają CookieStore (albo nowy, albo jeden zapisany z poprzedniej życzenie):

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

Oczywiście, można dodać cookies do instancji CookieStore przed wysłaniem żądania Jeśli lubisz. Teraz, gdy wywołujemy metodę Execute wykorzystać tę instancję HttpContext:

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

(gdzie httpRequester jest instancją HttpPost, HttpGet, etc.)

Jeśli trzeba ponownie wysyłać żadnych plików cookie na kolejnych wniosków, upewnij się, zapisać ciasteczka gdzieś:

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

Klasa StaticCacheHelper, który jest używany w tym kodzie jest tylko klasa zwyczaj, że może przechowywać dane w statyczna mapa

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

ALE !!!! Od 01/2012 RestTemplate na wiosnę Android nie daje dostępu do dodania HttpContext do wykonania żądania !! Zostało to naprawione w Spring Framework 3.1.0.RELEASE i ta poprawka to scheduled to be migrated into Spring Android 1.0.0.RC1.

Tak więc, gdy otrzymamy Spring Android 1.0.0.RC1, powinniśmy być w stanie dodać kontekst, jak opisano w powyższym przykładzie. Do tego czasu musimy dodawać/wyciągać pliki cookie z nagłówków żądania/odpowiedzi za pomocą 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 przechwytuje żądania, patrzy w pamięci podręcznej, aby zobaczyć, czy są jakieś ciasteczka dodać do wniosku, następnie wykonuje wniosek, następnie wyciąga żadnych ciasteczek off odpowiedzi i przechowuje ją do późniejszego wykorzystania.

Dodaj do przechwytywania szablonu żądanie:

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

I nie udać! Testowałem to i to działa. To powinno Cię zatrzymać aż do Spring Android 1.0.0.RC1, kiedy możemy użyć HttpContext bezpośrednio z RestTemplate.

Nadzieja, że ​​to pomaga innym !!

Powiązane problemy