springboot web项目中 Set-Cookie 失败 办法

news2024/9/24 0:50:04

1. 背景

目前有个项目 线上环境 使用spring session管理的登录
项目中有两个接口

一个用来登录的 登录成功后会设置cookie 后续请求就会使用该cookie (cookie的键值就是session Id 和 登录后的信息 例如菜单,权限等)

一个用来检查是否登录的 根据session id 来判断是否登录 没有登录信息的 直接返回未登录

调用登录成功后 发现Set-Cookie 出现响应头中 但是 调用检查接口发现还是还是未登录

如下图 模拟登录接口 响应中正确返回了 session
在这里插入图片描述
但是检查登录却未将 模拟登陆返回的接口携带上 导致登录校验失败
在这里插入图片描述

2. 问题排查

刚开始怀疑两次请求的session id 不一致导致无法使用 模拟登录返回的cookie 但是在测试环境时 可以校验登录接口正常使用 模拟登陆返回的session

模拟登录的接口
在这里插入图片描述
验证登录的接口
在这里插入图片描述
那问题好像不是session不一致的问题。
因为目前使用spring-session来管理session 如果登录成功后 会将session id 以及登录信息 设置到cookie 同时存入到浏览器 应用的 cookie中 同时会将session 存入到 redis中 其他的接口就会携带

那目前设置没问题 那登录成功后是否 将session 存入到到浏览器应用的cookie 直接去检查 发现没有设置上

在这里插入图片描述
这里发现 模拟登录成功后 并没有将session 存入到 浏览器应用的cookie中

那么问题就变成了 为什么 没有将session 存入到 浏览器应用的cookie中

接下来就是一步步的修改
首先可以明确的是 页面部署在A域名 接口部署在B域名 这种请求肯定是跨域的 所以我们要在接口的NGINX中添加 跨域配置

#在指定的接口路径中才添加
location /xxxx/ {
        add_header 'Access-Control-Allow-Origin' 'xxx';
        add_header 'Access-Control-Allow-Headers' '*';
        add_header 'Access-Control-Allow-Methods'  '*';
        proxy_set_header   Host             $host;
        proxy_set_header   X-Real-IP        $remote_addr;
        proxy_set_header   X-Forwarded-For  $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto  $scheme;
        #代理的配置 这个是虚拟网关的配置 每个项目不一定相同
        proxy_pass    http://gateway;
    }
  • 修改过程中 首先将登录接口中设置cookie 时增加sameSite 参数 并设置值为None 表示 允许在跨站点请求中发送
public static void setCookie(HttpServletResponse response, String cookieName, String value, int maxAgeExpiry) {
    //设置cookie 默认7天
    ResponseCookie cookie = ResponseCookie.from(cookieName, value)
            .httpOnly(true)		// 禁止js读取
            .secure(true)		// 在http下也传输
            .path("/")			// path
            .maxAge(maxAgeExpiry)
            // 新增加的部分 允许在跨站点请求中发送
            .sameSite("None")
            .build()
            ;

    // 设置Cookie Header
    response.setHeader(HttpHeaders.SET_COOKIE, cookie.toString());
    log.info("设置cookie完成,{}: {}", cookieName, cookie);
}
  • 其次在前端 vue的页面调用接口时增加 使用凭证参数 由于使用的时 vue的 axios 请求框架 直接在项目中增加 配置即可 axios.defaults.withCredentials = true;
    其他的方式 添加方式如下
使用vue.resource发送请求时配置如下:
main.js中 Vue.http.options.xhr = { withCredentials: true }
 
 
使用vue.axios发送请求时配置如下:
axios.defaults.withCredentials = true;
 
 
jquery请求带上 xhrFields: {withCredentials: true}, crossDomain: true;
$.ajax({
type: "post",
url: "",
xhrFields: {withCredentials: true},
crossDomain: true,
data: {username:$("#username").val()},
dataType: "json",
success: function(data){ }
});
  • 最后在接口的NGINX配置中同样添加使用凭证参数
add_header 'Access-Control-Allow-Credentials' 'true';

本来以为添加完 应该可以正常请求了 但是 比之前错误更明显了 接口都无法调用了

在这里插入图片描述
结果一看前端页面的控制台 看到如下错误 更有点百思不得其解
Access to XMLHttpRequest at ‘https://xxx/checkAuthorityUpdate’ from origin ‘https://xxx’ has been blocked by CORS policy: Request header field content-type is not allowed by Access-Control-Allow-Headers in preflight response.

居然提示请求头不被允许 但是我的接口 nginx配置

add_header 'Access-Control-Allow-Headers '*';

这个配置意思 应该是允许所有的请求头吧 但是查询了下,看下ai的解释

这个错误提示是因为在进行跨域请求时,浏览器在发送实际请求之前会先发送一个预检请求(OPTIONS请求),这个请求包含了实际请求的所有信息,包括请求头。服务器在接收到这个预检请求后,需要返回一个响应,告诉浏览器哪些请求头是允许的。

在你的配置中,add_header ‘Access-Control-Allow-Headers’ ‘*’;设置的是允许所有请求头,但是浏览器在发送实际请求时,可能只发送了部分请求头,所以服务器需要明确指定允许哪些请求头。

你可以通过add_header ‘Access-Control-Allow-Headers’ ‘Content-Type, Authorization’;来指定允许的请求头为 “Content-Type” 和 “Authorization”。这样,浏览器在发送实际请求时,只有这两个请求头会被发送,服务器在接收到这个请求后,也会只检查这两个请求头,就不会出现这个错误了。

所以我们再次修改请求的配置

add_header 'Access-Control-Allow-Headers' 'Origin, X-Requested-With, Content-Type, Accept, Authorization, Accept-Language';

然后就大家都欢喜,校验登录的接口 也可以正常使用模拟登录的session ,模拟登录的session也存入到了应用的cookie里


突然在测试某个功能 更新接口 居然提示跨域请求 一看控制台发现 put 方法不被允许 报错详细如下
access to XMLHttpRequest at ‘https://xxx/updateAuditResult’ from origin 'https://xxx has been blocked by CORS policy: Method PUT is not allowed by Access-Control-Allow-Methods in preflight response.

接口中的nginx配置

add_header 'Access-Control-Allow-Methods'  '*';

难道又是不允许* 我们改成具体的尝试下看看
修改为具体的method如下

add_header 'Access-Control-Allow-Methods' 'GET,POST,PUT,DELETE';

果然可以了,至此 set-cookie 问题 解决完成

最后来汇总下解决办法

  1. 接口的nginx 跨域配置 例如 headers和 method 中的* 配置修改为具体的
#xx为接口前缀 请注意配置 如果没有前缀可以放在 / 下
location /xxx/ {
        add_header 'Access-Control-Allow-Origin' 'xxx';
        add_header 'Access-Control-Allow-Headers' 'Origin, X-Requested-With, Content-Type, Accept, Authorization, Accept-Language';
        add_header 'Access-Control-Allow-Credentials' 'true';
        add_header 'Access-Control-Allow-Methods' 'GET,POST,PUT,DELETE';
        proxy_set_header   Host             $host;
        proxy_set_header   X-Real-IP        $remote_addr;
        proxy_set_header   X-Forwarded-For  $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto  $scheme;
        proxy_pass    http://gateway;
    }
  1. 接口中设置cookies的方法 增加 samsite属性 且 属性值为None
public static void setCookie(HttpServletResponse response, String cookieName, String value, int maxAgeExpiry) {
    //设置cookie 默认7天
    ResponseCookie cookie = ResponseCookie.from(cookieName, value)
            .httpOnly(true)		// 禁止js读取
            .secure(true)		// 在http下也传输
            .path("/")			// path
            .maxAge(maxAgeExpiry)
            // 新增加的部分 允许在跨站点请求中发送
            .sameSite("None")
            .build()
            ;

    // 设置Cookie Header
    response.setHeader(HttpHeaders.SET_COOKIE, cookie.toString());
    log.info("设置cookie完成,{}: {}", cookieName, cookie);
}
  1. 在前端 vue的页面调用接口时增加 使用凭证参数 由于使用的时 vue的 axios 请求框架 直接在项目中增加 配置即可 axios.defaults.withCredentials = true;
    其他的方式 添加方式如下
使用vue.resource发送请求时配置如下:
main.js中 Vue.http.options.xhr = { withCredentials: true }
 
 
使用vue.axios发送请求时配置如下:
axios.defaults.withCredentials = true;
 
 
jquery请求带上 xhrFields: {withCredentials: true}, crossDomain: true;
$.ajax({
type: "post",
url: "",
xhrFields: {withCredentials: true},
crossDomain: true,
data: {username:$("#username").val()},
dataType: "json",
success: function(data){ }
});

另外 登录成功session 不能生效问题有很多种 包括但不仅限于 如下

  • sessionID 不同问题 前后两个请求的session不同 请注意判断是否 是真的不一致 (例如说 我在登录接口中 将session设置成功 并成功保存到了应用的cookie中 然后在校验登录接口传入的sessionId 却是另一个 这种就属于 sessionID 不一致的 )
    解决: 这种问题不是很好找 需要排查是代码问题 还是使用的框架 问题 还是 接口NGINX配置问题
  • set-cookie 失效 参考文中解决办法
  • 登录请求和校验请求 cookie设置的domin 和 校验请求的domin不同 这种也会导致检验请求 无法使用 登录请求设置的 cookie 不过这种通常出现在 第三方授权中
    在这里插入图片描述
  • nginx配置的 Access-Control-Allow-Origin 和实际的 跨域地址不同 这个在页面控制台会报错 这个修改办法 将NGINX配置修改为和实际请求的地址一样即可

Access to XMLHttpRequest at ‘https://xxx/checkAuthorityUpdate’ from origin ‘https://xxx:8068’ has been blocked by CORS policy: Response to preflight request doesn’t pass access control check: The ‘Access-Control-Allow-Origin’ header has a value ‘https://xxx’ that is not equal to the supplied origin

  • 等等

god day ! ! !

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1143402.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

听GPT 讲Rust源代码--library/std(5)

File: rust/library/std/src/sys/unsupported/time.rs 在Rust源代码中,rust/library/std/src/sys/unsupported/time.rs文件的作用是提供对于时间的支持,特别是在不支持的操作系统上。 该文件中包含了两个结构体定义,分别是Instant和SystemTim…

confluence

confluence PS:此文档全部由docker部署 1.准备挂载目录 1.给mysql创建data volume卷 [rooti-1-17 ~]# docker volume create confluence-mysql 2.给mysql创建配置文件 [rooti-1-17 ~]# mkdir -p /u01/confluence/mysql/ [rooti-1-17 ~]# cd /u01/confluence/my…

linux--

一、crond 任务调度 1、原理示意图 2、crontab 进行定时任务的设置 2.1. 概述 任务调度,是指系统在某个时间执行的特定的命令或程序。任务调度分类: 系统工作: 有些重要的工作必须周而复始地执行。如病毒扫描等 个别用户工作:个别用户可能希望执行某些…

springboot心理咨询管理系统

springboot心理咨询管理系统,java心理咨询管理系统,心理咨询管理系统 运行环境: JAVA版本:JDK1.8 IDE类型:IDEA、Eclipse都可运行 数据库类型:MySql(8.x版本都可) 硬件环境&#xf…

基于Qt串口Serial Port配置纯代码实现(桌面和嵌入式平台)

## Serial Port Qt 提供了串口类,可以直接对串口访问。我们可以直接使用 Qt 的串口类编程即可,十分方便。Qt 串口类不仅在 Windows 能用,还能在 Linux 下用,虽然串口编程不是什么新鲜事儿,既然 Qt 提供了这方面的接口,我们就充分利用起来,这将会使我们的开发十分方便!…

力扣刷题 day57:10-27

1.将数组划分成相等数对 给你一个整数数组 nums ,它包含 2 * n 个整数。 你需要将 nums 划分成 n 个数对,满足: 每个元素 只属于一个 数对。 同一数对中的元素 相等 。 如果可以将 nums 划分成 n 个数对,请你返回 true &#x…

Java面试八股文之暑假合集

八股文暑假合集 基础篇二分查找 java基础篇7月12号面向对象和面向过程的区别重载和重写String 7月13号自动装箱和拆箱静态方法构造方法成员变量和局部变量对象引用和对象实例返回值 与equals(重要)hashcode()和equals()HashMap 7月16号线程,进程和程序final关键字的…

fastadmin分类下拉(多级分类)使用教程

效果图1: 在后台分类管理中,添加需要的分类数据 效果图2: 在后台添加页面,点击下拉即可出现分类多级下拉数据 以上就是效果图。 分类下拉实现步骤: 1.更改控制器 找到需要修改的控制器,修改公共方法 _i…

matlab simulink PMSM_SVPWM PI转速控制

1、内容简介 略 8-可以交流、咨询、答疑 2、内容说明 略PMSM_SVPWM PI转速控制 PMSM SVPWM PI转速控制 3、仿真分析 4、参考论文 略

推理还是背诵?通过反事实任务探索语言模型的能力和局限性

推理还是背诵?通过反事实任务探索语言模型的能力和局限性 摘要1 引言2 反事实任务2.1 反事实理解检测 3 任务3.1 算术3.2 编程3.3 基本的句法推理3.4 带有一阶逻辑的自然语言推理3.5 空间推理3.6 绘图3.7 音乐3.8 国际象棋 结果5 分析5.1 反事实条件的“普遍性”5.2…

线程池的理解

线程池 线程池本质上是一种池化技术,而池化技术是一种资源复用的思想,比较常见的有连接池、内存池、对象池。 而线程池里面复用的是线程资源,它的核心设计目标,有两个: 减少线程的频繁创建和销毁带来的性能开销&#x…

【CSDN 每日一练 ★☆☆】【双指针】删除有序数组中的重复项

【CSDN Daily Practice】删除有序数组中的重复项 双指针 数组 题目 给你一个有序数组 nums ,请你 原地 删除重复出现的元素,使每个元素 只出现一次 ,返回删除后数组的新长度。 不要使用额外的数组空间,你必须在 原地 修改输…

读《GaitPart: Temporal Part-based Model for Gait Recognition》

2020在CVPR 摘要 人体的不同部分在行走过程中具有明显不同的视觉外观和运动模式。在最新的文献中,使用部分特征进行人体描述已被证实有利于个体识别。综上所述,我们假设人体的每个部分都需要自己的时空表达。然后,我们提出了一种新的基于部分…

C++入门04—数组与函数

1. 概述 所谓数组,就是一个集合,里面存放了相同类型的数据元素 特点1:数组中的每个数据元素都是相同的数据类型 特点2:数组是由连续的内存位置组成的 2. 一维数组 2.1 一维数组定义方式 一维数组定义的三种方式: …

全域数据连接器解决运营痛点问题,助力海尔节省200万+

随着电商渠道增多和数字技术发展,商家在全域运营和数字化建设方面的应用系统越来越多,诸如以天猫、京东等电商平台区分的店铺后台,以CRM、ERP、SCM等服务区分的应用软件。 这些系统数据各有侧重,但又独立运行,导致很多…

批量发送邮件时怎么使用蜂邮EDM与Outlook?

批量发送邮件时使用蜂邮EDM和Outlook的方法?群发电子邮件的技巧有哪些? 电子邮件仍然是最常用的沟通工具之一,无论是企业还是个人用户,都希望能够高效地一次性将邮件发送给多个收件人。在本文中,将深入探讨蜂邮EDM和O…

【耗时半年,实地调研!泣血2万字,破除你的人工智能焦虑!《2023最全AI商业落地调研报告》】发现一个不错的视频。

视频地址 学习视频地址: https://www.bilibili.com/video/BV1YB4y1f7GE/ 基金报告生成工具: https://www.anthropic.com/app-unavailable-in-region?utm_sourcecountry 国内不支持。 数据分析师要被淘汰 https://www.bilibili.com/video/BV17N41127P…

21、Python -- 如何定义类

目录 类和对象语法语法说明Python是动态语言类变量实例变量 实例方法 了解类与对象 掌握定义类的语法 理解Python的动态性 实例方法 类和对象 两个重要概念:类(class)和对象(object,也被称为实例,instance…

浅谈安科瑞EMS能源管控平台建设的意义-安科瑞 蒋静

摘 要:能源消耗量大、能源运输供给不足、环境压力日趋增加、能耗双控等一系列问题一直困扰着钢铁冶金行业,制约着企业快速稳定健康发展。本文介绍的安科瑞EMS能源管控平台,采用自动化、信息化技术,实现从能源数据采集、过程监控、…

Spring Web MVC入门

一:了解Spring Web MVC (1)关于Java开发 🌟Java开发大多数场景是业务开发 比如说京东的业务就是电商卖货、今日头条的业务就推送新闻;快手的业务就是短视频推荐 (2)Spring Web MVC的简单理解 💗Spring Web MVC:如何使…