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 混淆、失效的问题!

总结

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

相关文章

  • springboot集成mybatisplus的详细步骤

    springboot集成mybatisplus的详细步骤

    MyBatis-Plus (opens new window)(简称 MP)是一个 MyBatis (opens new window)的增强工具,在 MyBatis 的基础上只做增强不做改变,为简化开发、提高效率而生,这篇文章主要介绍了springboot四步集成mybatisplus,需要的朋友可以参考下
    2022-10-10
  • SpringBoot远程访问redis服务器问题剖析

    SpringBoot远程访问redis服务器问题剖析

    使用了SpringBoot的项目,在远程连接Redis服务器时,会遇倒一些小问题,下面通过本文给大家全面解析SpringBoot远程访问redis服务器问题,需要的朋友参考下吧
    2017-04-04
  • Java 通过 二三法 巧解前端数据显示

    Java 通过 二三法 巧解前端数据显示

    实践来源于理论,做开发前肯定要先了解相关的规则和原理,看到标题或许你会好奇什么是二三法。本篇文章带你深入了解,需要的朋友可以参考下
    2021-10-10
  • Java Socket实现聊天室附1500行源代码

    Java Socket实现聊天室附1500行源代码

    Socket是应用层与TCP/IP协议族通信的中间软件抽象层,它是一组接口。本篇文章手把手带你通过Java Socket来实现自己的聊天室,大家可以在过程中查缺补漏,温故而知新
    2021-10-10
  • spring boot 配置freemarker及如何使用freemarker渲染页面

    spring boot 配置freemarker及如何使用freemarker渲染页面

    springboot中自带的页面渲染工具为thymeleaf 还有freemarker这两种模板引擎,本文重点给大家介绍spring boot 配置freemarker及如何使用freemarker渲染页面,感兴趣的朋友一起看看吧
    2023-10-10
  • 深入浅出探究Java多态的实现和应用

    深入浅出探究Java多态的实现和应用

    多态是实现面向对象的软件技术中必不可少的一个内容,所以这篇文章主要来和大家讲解一下Java多态的实现和应用,感兴趣的小伙伴可以了解一下
    2023-07-07
  • Spring集成MyBatis 及Aop分页的实现代码

    Spring集成MyBatis 及Aop分页的实现代码

    这篇文章主要介绍了Spring集成MyBatis 及Aop分页的实现,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2023-04-04
  • SpringBoot 整合ChatGPT API项目实战教程

    SpringBoot 整合ChatGPT API项目实战教程

    这篇文章主要介绍了SpringBoot整合ChatGPT API项目实战教程,本文通过示例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2023-05-05
  • spring使用validation参数及全局异常检测方式

    spring使用validation参数及全局异常检测方式

    本文主要介绍了Java的数据校验规范validation-api,包括其定义的注解和HibernateValidator的实现,还介绍了spring-boot-starter-validation的使用,可以让开发者在SpringBoot应用中简化数据校验的功能
    2025-02-02
  • openEuler 搭建java开发环境的详细过程

    openEuler 搭建java开发环境的详细过程

    这篇文章主要介绍了openEuler 搭建java开发环境,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2022-06-06

最新评论