缘由
最近开发新项目,在过程中遇到session获取数据为空的问题。查阅很多资料,现在做一下记录。由于将TP6升级至TP8,composer部分插件并不支持TP8,故而需要更换。其中管理页面的验证码图片edward1108/edward-captcha 插件就是这样。
在将整体升级后,这个组件会由于php8的特性,无法继续使用动态属性,故而报错。去packagist.org上寻找替代品,发现了tp官方有相应的拓展包,topthink/think-captcha便改用了TP的拓展包。根据教程将app\middleware.php中的\think\middleware\SessionInit::class注释解除,然后开始调试代码。
// 生成验证码代码替换
//$data = edward\captcha\facade\CaptchaApi::create()
think\captcha\facade\Captcha::create()
$data = Captcha::create();
$data = [ //为了兼容,为了不修改前端代码
'base64' => $data['img'],
'md5' => md5($data['code']),
'key' => md5($data['code'])
];
return $data;
// 校验验证码代码替换
//edward\captcha\facade\CaptchaApi::check($code, $key)
think\captcha\facade\Captcha::check($code);发现问题
在解决完上述切换验证码组件的问题后,界面显示了验证码图片,本以为一切完美。结果,在校验时,却怎么都无法校验成功。由于之前有遇到过相同的情况,很快就联想到了是cookie问题。
通过图片可以看到,php是响应了Set-Cookie头属性的,并设置了sessionid。然而在下面图片中的cookie表中完全没看到。

解题过程
Thinkphp项目中存在config/cookie.php文件,文件中可见如下设置选项:
return [
// cookie 保存时间
'expire' => 0,
// cookie 保存路径
'path' => '/',
// cookie 有效域名
'domain' => 'nutrition.cc',
// cookie 启用安全传输
'secure' => false,
// httponly设置
'httponly' => true,
// 是否使用 setcookie
'setcookie' => true,
// samesite 设置,支持 'strict' 'lax'
'samesite' => 'strict',
];
HttpOnly
HttpOnly 字段 cookie的httponly属性。若此属性为true,则只有在http请求头中会带有此cookie的信息,而不能通过 document.cookie 来访问此 cookie。这样能有效的防止XSS攻击。窃取cookie内容,这样就增加了cookie的安全性。1
也就是说如果设置为true,则前端代码无法获取到该cookie,且无法操作该cookie。
Secure
secure属性可防止信息在传递的过程中被监听捕获后导致信息泄露,如果设置为true,可以限制只有通过https访问时,才会将浏览器保存的cookie传递到服务端,如果通过http访问,不会传递cookie。2
如果设置为true,则这个cookie只在https的站点中生效,http无效。
SameSite
这项可以设置三个选项:
Strict
Strict最为严格,完全禁止第三方 Cookie,跨站点时,任何情况下都不会发送 Cookie。换言之,只有当前网页的 URL 与请求目标一致,才会带上 Cookie。3
这个选项必须是域名(包含子域名)完全一致,才可以传递cookie。
Lax
Lax规则稍稍放宽,大多数情况也是不发送第三方 Cookie,但是导航到目标网址的 Get 请求除外。3
None
Chrome 计划将
Lax变为默认设置。这时,网站可以选择显式关闭SameSite属性,将其设为None。不过,前提是必须同时设置Secure属性(Cookie 只能通过 HTTPS 协议发送),否则无效。3
None是最宽松的控制项,但不利于开发环境,因为该选项必须配合Secure=true来使用,也就是网站必须开通https功能。
Domain
Domain指定了哪些主机可以接受 Cookie。如果不指定,该属性默认为同一 host 设置 cookie,不包含子域名。如果指定了Domain,则一般包含子域名。因此,指定Domain比省略它的限制要少。但是,当子域需要共享有关用户的信息时,这可能会有所帮助。4
但经过多次测试,暂时无法实现子域名之间的cookie传递。
解决方法
目前唯一能解决的方法,就是做nginx代理,将域名下的某一个子目录代理为前端代码。

感谢:
1.cookie中数据无法读取,HttpOnly属性 - 马文庆i - 博客园
2.HTTP Cookie header 中set-cookie格式及安全secure httponly - silyvin - 博客园