在进行HTTP调用之前使用RestTemplate清除Cookies

时间:2018-06-04 11:46:54

标签: java cookies session-cookies resttemplate

我使用Spring-Boot 2.0.2 RestTemplate来制作以下场景:

我是休息 - 消费者(客户),其中:

  1. 首先需要登录Spring-Security-Check
  2. 然后再拨打电话获取数据。
  3. 首先,我正在考虑进行auth调用并从SET-COOKIE手动读取JSESSIONID Cookie并在标头中的第二次调用中设置它。这是我的第一次尝试:

    RestClient:

    @Service
    public class RestClient {
        private static final String ENDPOINT_DATA = "/data";
        private static final String ENDPOINT_SECURITY_CHECK = "/j_spring_security_check";
    
        private static final String HTTP_HEADER_KEY_SET_COOKIE = "Set-Cookie";
        private static final String HTTP_HEADER_KEY_COOKIE = "Cookie";
    
        private static final String PROPERTY_SPRING_SECURITY_USER = "j_username";
        private static final String PROPERTY_SPRING_SECURITY_PASS = "j_password";
    
        private final RestTemplate restTemplate;
        private final RestConfig restConfig;
    
        @Autowired
        public RestClient(RestTemplateBuilder restTemplateBuilder, final RestConfig restConfig) {
    
            notNull(restTemplateBuilder, "restTemplateBuilder must not be null!");
            this.restTemplate = restTemplateBuilder
                    .additionalCustomizers(new NoRedirectionHandlingRestTemplateCostumizer())
                    .build();
    
            notNull(restConfig, "openIdConfig must not be null!");
            this.restConfig = restConfig;
        }
    
        public String getData() {
            final String jSessionCockie = jSpringSecurityLogin();
            return getAuthorizeCode(jSessionCockie);
        }
    
        private String jSpringSecurityLogin() {
            // read config
            final String fullLoginUri = restConfig.getUrl() + ENDPOINT_SECURITY_CHECK;
            final String user = restConfig.getUser();
            final String password = restConfig.getPassword();
    
            // Build entity that is send
            final HttpHeaders headers = new HttpHeaders();
            final String body = PROPERTY_SPRING_SECURITY_USER + "=" + user + "&" + PROPERTY_SPRING_SECURITY_PASS + "=" + password;
            final HttpEntity<String> toSend = new HttpEntity<>(body, headers);
    
            final String jSessionIdCockie;
    
            final ResponseEntity<String> response = restTemplate.postForEntity(fullLoginUri, toSend, String.class);
    
            // Get String "JSESSIONID=XXXX". If there are other Cookies, propably will fail.
            if (HttpStatus.FOUND.equals(response.getStatusCode()) && response.getHeaders().containsKey(HTTP_HEADER_KEY_SET_COOKIE)) {
                jSessionIdCockie = response.getHeaders().get(HTTP_HEADER_KEY_SET_COOKIE).get(0);
            } else {
                throw new Error();
            }
    
            return jSessionIdCockie;
        }
    
        private String getAuthorizeCode(final String jSessionCockie) {
            // read config
            final String fullDataUri = restConfig.getUrl() + ENDPOINT_DATA;
    
            // Build entity that is send
            final HttpHeaders headers = new HttpHeaders();
            headers.add(HTTP_HEADER_KEY_COOKIE, jSessionCockie);
            final HttpEntity<Void> toSend = new HttpEntity<>(headers);
    
            final ResponseEntity<String> response = restTemplate.exchange(fullDataUri, HttpMethod.GET, toSend, String.class);
    
            if (HttpStatus.OK.equals(response.getStatusCode()) && response.hasBody()) {
                return response.getBody();
            } else {
                return "";
            }
        }
    }
    

    要完成,请在构造函数中使用Costumizer:

    class NoRedirectionHandlingRestTemplateCostumizer implements RestTemplateCustomizer {
        @Override
        public void customize(RestTemplate restTemplate) {
            final HttpClient httpClient = HttpClientBuilder.create()
                    .disableRedirectHandling()
                    .build();
            restTemplate.setRequestFactory(new HttpComponentsClientHttpRequestFactory(httpClient));
        }
    }
    

    现在,当我使用Wiremock进行一些功能测试时,我会在数据通话的线索请求历史记录中看到:

    {
      ...
      "headers":
      {
        "Cookie": [
          "JSESSIONID=axcvueiornxniuwherwuieoiun,asdpfoiu",
          "JSESSIONID=axcvueiornxniuwherwuieoiun,asdpfoiu"
        ],
        ...
      },
      "cookies":
      {
        "JSESSIONID": [
          "axcvueiornxniuwherwuieoiun,asdpfoiu",
          "axcvueiornxniuwherwuieoiun,asdpfoiu"
        ]
      }
      ...
    }
    

    等待 - JSESSIONID设置了2次。酷REST为我处理它!

    第二次尝试:我可以删除Cookie处理。它有效。

    但是第一次和第二次尝试都有问题:在RestClient.getData()的第一次调用之后,对login-Endpoint的所有后续调用也都设置了JSESSIONID。我不知道Rest-Producer如何处理这个问题(Session-timeout e.c.t.)。

    现在我的问题/问题:

    我想在进行登录呼叫之前强制RestTemplate忘记/清除所有Cookie(之前的原因说明)。有可能吗?我没有找到任何有用的东西。

    我现在的解决方法是禁用RestTemplate的Cookie管理,并像第一次尝试一样手动完成。可以通过RestTemplateCustomizer

    来禁用CookieManagment
    class NoRedirectionHandlingRestTemplateCostumizer implements RestTemplateCustomizer {
        @Override
        public void customize(RestTemplate restTemplate) {
            final HttpClient httpClient = HttpClientBuilder.create()
                    .disableRedirectHandling()
                    .disableCookieManagement()
                    .build();
            restTemplate.setRequestFactory(new HttpComponentsClientHttpRequestFactory(httpClient));
        }
    }
    

1 个答案:

答案 0 :(得分:2)

正如问题中提到的,首先我们需要通过以下方式禁用cookie管理

CloseableHttpClient httpClient = HttpClients.custom() .setConnectionManager(厘米) .setRetryHandler(retryHandler) .setKeepAliveStrategy(connectionKeepAliveStrategy) .disableCookieManagement() .evictExpiredConnections()。evictIdleConnections(10,TimeUnit.MINUTES) .build();

并像设置其他标题一样设置“ Cookie”标题。

公共ResponseEntity getContent(字符串url,Map 标头,Map cookie){ HttpHeaders requestHeaders = new HttpHeaders();

    // add headers
    for(String key : headers.keySet()){
        requestHeaders.set(key, headers.get(key));
    }

    // add cookies
    List<String> allCookieValues = new ArrayList<>();
    for(String key : cookies.keySet()){
        String value = cookies.get(key);
        String cookieString = MessageFormat.format("{0}={1}", key,value);
        allCookieValues.add(cookieString);
    }
    requestHeaders.addAll(HttpHeaders.COOKIE, allCookieValues);

    HttpEntity<String> httpEntity = new HttpEntity<String>(requestHeaders);
    UriComponentsBuilder builder = UriComponentsBuilder.fromUriString(url);
    URI uri = builder.build(true).toUri();
    ResponseEntity responseEntity = null;
    try {
        responseEntity = restTemplate.exchange(uri, HttpMethod.GET, httpEntity, byte[].class);

...... ......

在回复中,如果您想阅读,我们可以通过以下方式阅读cookie

列出responseCookies = responseEntity.getHeaders()。get(HttpHeaders.SET_COOKIE); Map cookieNameValue = new HashMap <>();

    if(requestCookies != null){
        cookieNameValue.putAll(requestCookies);
    }

    for(String cookie : responseCookies){
        String[] cookieParts = cookie.split(";")[0].split("=");
        cookieNameValue.put(cookieParts[0], cookieParts[1]);
    }
    return cookieNameValue;