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

 更新时间:2023年07月06日 10:54:29   作者:毕小宝  
这篇文章主要介绍了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。

// 请求参数
String token = request.getParameter("t");
// Cookie
if (StringUtils.isEmpty(token)) {
    Cookie[] cs = request.getCookies();
    if (cs != null) {
        for (Cookie c : cs) {
            if ("t".equals(c.getName())) {
                token = c.getValue();
                break;
            }
        }
    }
}
 //Header
if (StringUtils.isEmpty(token)) {
    token = request.getHeader("t");
}

问题症结

后台模块 A 一小时执行一次,每次调用使用 Spring 托管的 RestTemplate 单例对象发送请求给 B 时,它包含了上次请求收到的 Cookie 信息。

虽然同时生成了 Token 的头域信息,但是在 Web 端优先校验了 Cookie ,因此认证结果始终是无效 Token ,请求被拒绝。

启示录

我从互联网上得到的最好的经验之一,就是永远不要复制和粘贴不是自己编写的代码。

如果你一定要复制,那就照着它逐字输入,逼着自己思考,这些代码实际上是什么意思。

这是昨天看科技周刊印象深刻的一句话,本文的问题虽然不是复制粘贴导致的,但它别人的代码、别人的思想,我没有深刻分析过。

当我临时救火被分派解决这个问题时,简单看了下代码分析如下:

  • 后端服务设置 Token 到了头域
  • 而 Web 模块只从 Cookie 和请求参数中获取 Token ,没有从 Header 中获取

想当然地以为,只要加上从 Header 中获取就好了,而且阴差阳错的加在了 Cookie 获取的后面,所以问题还是没有解决。

反复加日志,打印各个信息的 Token ,发现解析时用的 Token 跟头域不一样, Token 失效时间也很规律,就是上次定时任务的调用时间。突然意识到了,Web 服务用的 Token 跟我想的不一样,谁把 Token 给改了?

答案是 Cookie,RestTemplate 竟然在发送请求时把上次的 Cookie 给带上了。30分钟的有效期,下一轮定时任务执行时,早就是失效了啊。

RestTemplate 注意事项

用 RestTemplate 进行服务调用时,最好清掉 Cookie 信息,

一来避免本文出现的情况;

二来,它作为Spring 托管的单例,如果访问的是不同系统的 API ,势必会出现 Cookie 混淆、失效的问题!

总结

以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。

相关文章

  • JVM性能调优之运行时参数小结

    JVM性能调优之运行时参数小结

    jvm是java的运行环境,在jvm中有很多的参数可以进行设置,本文主要介绍了JVM性能调优之运行时参数小结,具有一定的参考价值,感兴趣的可以了解一下
    2024-04-04
  • Netty与Spring Boot的整合实现

    Netty与Spring Boot的整合实现

    这篇文章主要介绍了Netty与Spring Boot的整合的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2019-08-08
  • Spring SpringMVC,Spring整合MyBatis 事务配置的详细流程

    Spring SpringMVC,Spring整合MyBatis 事务配置的详细流程

    这篇文章给大家介绍SSM整合详细流程步骤 Spring SpringMVC,Spring整合MyBatis 事务配置,本文通过实例图文相结合给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友参考下吧
    2020-10-10
  • SpringCloud之Zuul服务网关详解

    SpringCloud之Zuul服务网关详解

    这篇文章主要介绍了SpringCloud之Zuul服务网关详解,服务网关是微服务架构中一个不可或缺的部分,通过服务网关统一向外系统提供REST API的过程中,除了具备服务路由、均衡负载功能之外,它还具备了权限控制(鉴权)等功能,需要的朋友可以参考下
    2023-08-08
  • 关于springboot2整合lettuce启动卡住问题的解决方法

    关于springboot2整合lettuce启动卡住问题的解决方法

    Lettuce和Jedis的都是连接Redis Server的客户端程序,下面这篇文章主要给大家介绍了关于springboot2整合lettuce启动卡住问题的解决方法,文中通过示例代码介绍的非常详细,需要的朋友可以参考下
    2021-12-12
  • Java @SentinelResource全面介绍

    Java @SentinelResource全面介绍

    在实际应用过程中,我们可能需要限流的层面不仅限于接口。可能对于某个方法的调用限流,对于某个外部资源的调用限流等都希望做到控制。对此,我们需要学习使用@SentinelResource注解,灵活的定义控制资源以及如何配置控制策略
    2022-08-08
  • Spring整合Junit详解

    Spring整合Junit详解

    Spring 是目前主流的 Java Web 开发框架,是 Java 世界最为成功的框架。该框架是一个轻量级的开源框架,具有很高的凝聚力和吸引力,本篇文章带你了解如何配置数据源、注解开发以及整合Junit
    2022-07-07
  • Spring Boot 的创建和运行示例代码详解

    Spring Boot 的创建和运行示例代码详解

    Spring Boot 的诞生是为了简化Spring程序的开发,今天给大家介绍下Spring Boot 的创建和运行,主要包括Spring Boot基本概念和springboot优点,本文通过实例代码给大家介绍的非常详细,需要的朋友参考下吧
    2022-07-07
  • Java在web页面上的编码解码处理及中文URL乱码解决

    Java在web页面上的编码解码处理及中文URL乱码解决

    这篇文章主要介绍了Java在web页面上的编码解码处理及中文URL乱码解决,文中所介绍的两种使用过滤器解决中文链接乱码的方法非常有效,需要的朋友可以参考下
    2016-02-02
  • 详解springboot+mybatis多数据源最简解决方案

    详解springboot+mybatis多数据源最简解决方案

    本篇文章主要介绍了详解springboot+mybatis多数据源最简解决方案,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2017-05-05

最新评论