type
Post
status
Published
date
Feb 2, 2022
slug
summary
withCredentials: true 开启后仍需要设置 SameSite=None ,并开启 Tomcat 的 HTTPS 支持
tags
项目方案
category
技术分享
icon
password

跨域解决方案

跨域请求访问问题的后端Cros三种解决方案:
  • 局部:@CrossOrigin注解的origins 属性设置允许跨域访问的 URL
    • 设置后响应头上会添加上对应允许跨域的信息
  • 全局:SpringMVC 下的配置类实现WebMvcConfigurer接口,并重写addCorsMappings方法
  • 全局:全局过滤器类,拦截到响应后,给响应设置允许跨域相关的响应头
    • 允许跨域访问的来源:Access-Control-Allow-Origin
    • 不能设置为*,否则导致Access-Control-Allow-Credentials = true 的响应头失效
这样就解决了跨域访问问题,但遇到了新的问题:前端无法携带 Cookie 来访问接口

携带 Cookie

  • 前端需要加上withCredentials: true 属性,如果是用 vue axios发送的请求,需要在 main.js中配置
  • 后端在响应头中,需要加上:
response.setHeader("Access-Control-Allow-Credentials", "true");
查询搜索引擎和有关文档,了解到和 cookie 的 SameSite 属性有关

SameSite 属性

浏览器的 Cookie 信息可以用来保存登录信息来保持登录验证状态,并且随着请求自动发送到服务器,这就给了其他站点发起CSRF攻击和用户追踪的机会
cookie的SameSite属性,就是用来限制第三方网站的cookie发送机制
三种取值:
Set-Cookie: name=value;** SameSite=xxx;**
  • Strict 严格模式:完全禁止跨站请求携带 cookie
  • Lax 宽松模式:允许导航到第三方网站时携带,例如<a>跳转,<form>表单的提交
  • None 显式关闭 SameSite 模式,但同时,必须加上secure参数,即:
    • Set-Cookie: name=value; SameSite=None; Secure;
      加上 Secure 后,cookie只会在HTTPS中发送,也就是说只有在 https 协议下 cookie 发送才有效
      开启Secure 的方法是在 web.xml 中加上:
<session-config> <cookie-config> <secure>true</secure> </cookie-config> </session-config>
现在的问题就剩下:
  1. 如何开启SameSite=None 这个属性
  1. 如何开启 https 访问

操作步骤

查询相关资料得知:SameSite是Cookie在新的 web 标准中的属性,Servlet 4.0规范不支持SameSite cookie属性,servlet.http.Cookie 库中没有设置SameSite属性的方法,而在 HttpSession 中JSESSIONID的默认 Cookie中,虽然存在server.servlet.session.cookie.secure的配置项,但没有提供对应的修改方法,所以只能通过修改容器配置,来设置SameSite属性
  1. tomcat 下conf/context.xml 新增标签:
    1. <CookieProcessor sameSiteCookies="None" />
  1. 使用 jdk 提供的密钥生成工具生成密钥:
    1. notion image
      keytool -genkeypair -alias "tomcat" -keyalg "RSA" -keystore "apache-tomcat-7.0.77\bin\tomcat.keystore"
      输入相关信息和一个密钥口令,会在指定目录(一般指定在 tomcat/bin下)生成一个密钥文件
      修改server.xml 文件:
      原: <!-- <Connector port="8443" protocol="org.apache.coyote.http11.Http11NioProtocol" maxThreads="150" SSLEnabled="true"> <SSLHostConfig> <Certificate certificateKeystoreFile="conf/localhost-rsa.jks" type="RSA" /> </SSLHostConfig> </Connector> --> 现: <Connector port="8443" protocol="org.apache.coyote.http11.Http11NioProtocol" maxThreads="150" SSLEnabled="true" scheme="https" secure="true" clientAuth="false" sslProtocol="TLS" keystoreFile="/Users/admin/apache-tomcat-8.5.69/apache-tomcat-8.5.69/bin/tomcat.keystore" keystorePass="jjbbkk" />
      如果在 SpringBoot 下的内置 tomcat 中就更加简单,生成密钥后移动到 resourses 目录下,进行ssl 的配置 :
      server.port=8888 server.ssl.key-store=classpath:keystore.p12 server.ssl.key-store-password=123456(此处密码为第一步中创建.p12文件时你输入的口令) server.ssl.keyStoreType=PKCS12 server.ssl.keyAlias=tomcat

      参考资料

      前后端分离Cookie sameSite坑 跨域之坑_行走在冬瓜地的西瓜的博客-CSDN博客_后端samesite
      在前后端分离解决跨域问题过程中,利用CORS解决跨域问题,前后端按照规范处理了,但不管怎样session都是不一致,所以前端无法登陆无法在本地测试。查了几天资料,中间反反复复,最后要放弃的时候无意中看到一个大神的博客。 本项目是使用spring-session-data-redis实现HTTP Session集中管理原理 SameSite Cookie 应该是一种新的cookie属性值,我看到很多大型网站如百度都没有用到, 他是防止 CSRF 攻击 具体可看 https://www.cnblogs.com/ziyunfei/p/5637945.html spring web 最新版默认生成为SameSite=Lax,奇怪的是用spring-session-data-redis 后 cookie新增了 SameSite这个字段,所以不能携带cookie进行跨域post访问,文档上也不表明什么时候开始的,坑的是默认为Lax也不能设置, 遂现在将web版本降级 因为服务端返回给客户端的set-cookie中带有samesite=lax,这就是问题的根源,它表示不能携带cookie进行跨域post访问,然而我们是需要携带cookie的 解决办法: @Bean public CookieSerializer httpSessionIdResolver(){ DefaultCookieSerializer cookieSerializer = new DefaultCookieSerializer(); cookieSerializer.setCookieName("token"); cookieSerializer.setUseHttpOnlyCookie(false); cookieSerializer.setSameSite(null); return cookieSerializer; } 使用的pom依赖 org.springframework.session spring-session-data-redis 2.1.1.RELEASE 前端在与后台交互时也得做如下的配置(ajax请求) xhrFields: { withCredentials: true } 它让ajax能够携带cookie请求,后端需要设置 response.setHeader("Access-Control-Allow-Credentials", "true"); 允许cookie跨域,这样就大功告成!!!
      前后端分离Cookie sameSite坑 跨域之坑_行走在冬瓜地的西瓜的博客-CSDN博客_后端samesite
Golang 日志库实现领域模型对象介绍和对比