RestTemplate 发送请求 清除Cookie

RestTemplate 发送请求时 Cookie 的影响及注意事项

背景

​ 一个基于 SpringCloud 的多服务项目中,服务间调用通过 Spring 的 RestTemplate 实现,后台模块 A 有一个定期清理无效业务数据的任务,它调用 Web 服务 B 的 API 时,竟然一直出现 Token 已过期问题。

技术背景:

Web 服务权限认证使用 Token ,登录校验成功后,刷新 Token 并调用 response.addCookie 返回给调用方——浏览器或者内部服务。
Web 服务的拦截器,它提取 Token 的顺序是:请求参数、Cookie、Header,然后验证 Token 的有效性。校验通过,刷新 Token 到响应对象的 Cookie 中。
Token 有效期限 30 分钟。
后台定时任务模块 A 每小时调用一次模块 B 的的 API 。
对于 Web 服务模块 B 来说,请求来源有用户浏览器和内部服务 A ,Token 校验通过后会刷新并设置响应对象的 Cookie 中,而 Cookie 又会在下次请求时发送给服务器。

各服务稳定运行后,定时任务 A 调用服务 B 的 API,从来都没有成功过。

后台服务调用时 Cookie 失效问题

问题描述:后台服务 A 在调用 B 的 某API 时,虽然会生成新 Token 信息并设置到头域,但是除了应用启动时成功调用了一次,其他周期的调用都出现了 Token 已过期问题。

问题分析:分析整个认证过程,发现在 Web 的拦截器中,如果检测到了内部服务调用,会刷新 Token 信息并返回给 RestTemplate 对象,而且拦截器提取 Token 的顺序是:请求参数、Cookie、Header。
问题症结

​ 后台模块 A 一小时执行一次,每次调用使用 Spring 托管的 RestTemplate 单例对象发送请求给 B 时,它包含了上次请求收到的 Cookie 信息。虽然同时生成了 Token 的头域信息,但是在 Web 端优先校验了 Cookie ,因此认证结果始终是无效 Token ,请求被拒绝。

解决:

在创建 RestTemplate 时,将构造好的参数填充到 RestTemplate 的属性中, 使用 disableCookieManagement 清楚 RestTemplate 中的 Cookie

import lombok.extern.slf4j.Slf4j;
import org.apache.http.conn.ssl.NoopHostnameVerifier;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.conn.ssl.TrustStrategy;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.ssl.SSLContexts;
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;

import javax.net.ssl.SSLContext;
/**
 * @author jiaohongtao
 */
@Slf4j
public class RestTemplateUtil {
	public static HttpComponentsClientHttpRequestFactory generateHttpsRequestFactory() {
		try {
			TrustStrategy acceptingTrustStrategy = (x509Certificates, authType) -> true;
			SSLContext sslContext = SSLContexts.custom()
					.loadTrustMaterial(null, acceptingTrustStrategy).build();
			SSLConnectionSocketFactory connectionSocketFactory = new SSLConnectionSocketFactory(
					sslContext, new NoopHostnameVerifier());

			HttpClientBuilder httpClientBuilder = HttpClients.custom();
			// 添加了ssl,没有的话可以不加
			// httpClientBuilder.setSSLSocketFactory(connectionSocketFactory);
			CloseableHttpClient httpClient = httpClientBuilder
					// 清除 RestTemplate 发送请求时的 Cookie,场景:多登录情况 cookie 不一致问题
					.disableCookieManagement()
					// 不支持重定向
					// .disableRedirectHandling()
					.build();
			HttpComponentsClientHttpRequestFactory factory = new HttpComponentsClientHttpRequestFactory();
			factory.setHttpClient(httpClient);
			factory.setConnectTimeout(10 * 1000);
			factory.setReadTimeout(30 * 1000);
			return factory;
		} catch (Exception e) {
			throw new RuntimeException("创建HttpsRestTemplate失败", e);
		}
	}
}

使用时:可以看到 声明 RestTemplate时 使用了构造方法

private RestTemplate restTemplate = new RestTemplate(RestTemplateUtil.generateHttpsRequestFactory());

参考文献:
RestTemplate 发送请求时 Cookie 的影响及注意事项
在进行 HTTP 调用之前使用 RestTemplate 清除 Cookie(clear Cookies with RestTemplate before make HTTP-call)
RestTemplate 重定向问题 &cookie问题

你可能感兴趣的:(Java,java,RestTemplate,Cookie)