2011-08-18 2 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 인증서를 신뢰 안드로이드의 HTTPS 문제를 분류 할 수 있었다 ClientHttpRequestFactory의 단일 구현을 사용하십시오.

1) 사용)를 사용하여 쿠키를 처리하는 방법 HttpComponentsClientHttpRequestFactory

3를 찾을 수) 내가 가진

+1

HttpUtils 링크에 감사드립니다. SSL과 다른 힌트에 대한 해결책을 찾지 못해 절실했다. – Solata

답변

8

다른 접근 방식을

2 SimpleClientHttpRequestFactory

를 사용하여 HTTPS를 처리 할 수있는 방법을 찾을 : 그래서 나는 3 가지 옵션이 있습니다 같은 문제. 여기 내 해결책은 다음과 같습니다.

먼저 SSL을 처리했습니다 (나는 Bob Lee의 방법을 사용했습니다).

쿠키는 다른 이야기입니다. 이전에 RestTemplate없이 쿠키를 처리 한 방식 (즉, Apache의 HttpClient 클래스를 직접 사용하는 것)은 HttpContext의 인스턴스를 HttpClient의 execute 메소드에 전달하는 것입니다.

execute(HttpUriRequest request, HttpContext context) 

이있는 HttpContext의 인스턴스가의 CookieStore에 대한 참조를 가질 수 있습니다

HttpClient를

은 하나의 오버로드 execute 메소드를 가지고 ... 이제 다시 단계를 보자. 물론

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)을 제공 네가 원한다면.

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

(여기서 httpRequester는 HttpPost, HttpGet 등의 인스턴스 인 : 당신이 실행 메서드를 호출 할 때 지금으로 HttpContext의 인스턴스를 사용)

당신이 어딘가에 쿠키를 저장할 수 있는지 확인 이후 요청에 쿠키를 다시해야하는 경우 :

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

하지만 !!!! 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까지 유지해야합니다.

다른 사람들에게 도움이되기를 바랍니다 !!