客户刚收到重置密码邮件,点击却提示链接无效或已过期,先不要反复延长 Token 有效期。这个问题经常由多网站范围、邮件链接域名、服务器时间或模板变量错误造成;有效期只是最后才检查的一项。
用一个专用测试客户记录完整请求
- 在对应网站创建测试客户,记录 website_id 和邮箱。
- 只点击一次“忘记密码”,保存邮件原始链接。
- 不要转发公开链接,Token 等同临时凭据。
- 在无痕窗口打开,并记录最终跳转 URL 与提示时间。
若邮件中的域名属于另一个网站,先修 Base URL 和邮件发送范围,不要修改数据库 Token。
核对客户记录与服务器时间
date -u
timedatectl status
php -r 'echo date(DATE_ATOM), PHP_EOL;'
SELECT entity_id, website_id, email, rp_token_created_at,
CASE WHEN rp_token IS NULL THEN 'empty' ELSE 'present' END AS token_state
FROM customer_entity
WHERE email='test@example.com';
数据库只确认 Token 是否生成以及生成时间,不要把 rp_token 输出到聊天、工单或监控日志。Web 节点、Cron 节点和数据库时间应一致;容器时区不同并不必然有问题,但 UTC 时间必须对齐。若 NTP 漂移数分钟,刚生成的 Token 也可能被判断为未来或过期。
检查配置范围而不是只看 Default Config
php bin/magento config:show customer/password/password_reset_protection_type
php bin/magento config:show customer/password/reset_link_expiration_period
php bin/magento store:list
后台切换到发生问题的网站 Scope,再核对 Customers 配置。多网站共享邮箱时,客户实体可能属于网站 A,而用户从网站 B 请求重置;请求看似成功,实际找到的客户范围不一致。此时要确认客户账号共享设置和前台表单运行的 website_id。
检查邮件模板生成的链接
恢复到默认模板做一次对照测试。自定义模板常见错误包括:把 customer id 当作 token、漏掉 id 参数、对 URL 再次 HTML 编码,或硬编码成错误域名。查看邮件源代码,确认查询参数没有被邮件系统安全重写截断。
curl -sSI 'https://shop.example.com/customer/account/createPassword/?id=123&token=REDACTED'
实际测试时使用真实链接,但不要把它写进 shell history;可以临时放入受限变量,测试后立即清除。若代理把 HTTPS 改回 HTTP,检查 X-Forwarded-Proto 与 secure Base URL。
Token 是否被第二次请求提前消耗
部分邮件安全网关会在客户点击前扫描链接。对访问日志按测试客户的 createPassword 路径和时间检索,判断是否已有机器人请求:
grep 'customer/account/createPassword' /var/log/nginx/access.log | tail -n 30
如果安全扫描器首先访问并导致业务逻辑改变,应修扩展代码:GET 只展示表单,真正修改密码必须由带 form key 的 POST 完成。不能通过关闭邮件安全扫描来掩盖不安全实现。
修复后重新发起一次全新的重置请求,因为旧 Token 可能已被覆盖。回归时测试同网站、跨网站、链接临近有效期、链接重复使用四种情况;密码修改成功后旧链接必须失效,这一点不能为了“好用”而取消。

