我使用Spring-Boot 2.0.2 RestTemplate
来制作以下场景:
我是休息 - 消费者(客户),其中:
首先,我正在考虑进行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
:
class NoRedirectionHandlingRestTemplateCostumizer implements RestTemplateCustomizer {
@Override
public void customize(RestTemplate restTemplate) {
final HttpClient httpClient = HttpClientBuilder.create()
.disableRedirectHandling()
.disableCookieManagement()
.build();
restTemplate.setRequestFactory(new HttpComponentsClientHttpRequestFactory(httpClient));
}
}
答案 0 :(得分:2)
正如问题中提到的,首先我们需要通过以下方式禁用cookie管理
CloseableHttpClient httpClient = HttpClients.custom() .setConnectionManager(厘米) .setRetryHandler(retryHandler) .setKeepAliveStrategy(connectionKeepAliveStrategy) .disableCookieManagement() .evictExpiredConnections()。evictIdleConnections(10,TimeUnit.MINUTES) .build();
并像设置其他标题一样设置“ Cookie”标题。
公共ResponseEntity getContent(字符串url,Map
// 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
if(requestCookies != null){
cookieNameValue.putAll(requestCookies);
}
for(String cookie : responseCookies){
String[] cookieParts = cookie.split(";")[0].split("=");
cookieNameValue.put(cookieParts[0], cookieParts[1]);
}
return cookieNameValue;