
本文介绍一种无需 mysql 事件即可安全、高效地实现密码重置链接 15 分钟自动失效的方案:在验证阶段动态校验时间戳,而非依赖数据库定时清理,兼顾安全性、可维护性与兼容性。
本文介绍一种无需 mysql 事件即可安全、高效地实现密码重置链接 15 分钟自动失效的方案:在验证阶段动态校验时间戳,而非依赖数据库定时清理,兼顾安全性、可维护性与兼容性。
在用户密码找回流程中,“链接过期”本质是时效性验证问题,而非数据清理问题。直接通过 MySQL Event 在后台定时清空 recuperar_senha 和 expiracao 字段,不仅存在明显缺陷(如事件权限限制、无法按用户粒度精准触发、调试困难、共享主机通常禁用 EVENT 权限),还会引入不必要的复杂性与潜在竞态风险。
✅ 推荐方案:服务端即时校验(推荐指数 ★★★★★)
在用户访问 /atualizar_senha.php?token=xxx 时,不依赖后台定时任务,而是立即执行三步验证:
- 查询该 token 对应的用户记录;
- 检查
expiracao时间是否非空且有效; - 计算当前时间与
expiracao的时间差,判断是否 ≤ 15 分钟。
示例验证逻辑(atualizar_senha.php 中):
<?php if (!isset($_GET['token']) || empty($_GET['token'])) {
die('Token inválido.');
}
$token = $_GET['token'];
// 查询匹配的用户(注意:expiracao 应为 DATETIME 类型)
$stmt = $conn->prepare("SELECT id, recuperar_senha, expiracao FROM login WHERE recuperar_senha = ? LIMIT 1");
$stmt->execute([$token]);
$user = $stmt->fetch(PDO::FETCH_ASSOC);
if (!$user) {
die('Token não encontrado ou já utilizado.');
}
// 安全的时间比较:使用 strtotime() + time(),避免时区歧义(确保数据库和 PHP 使用相同时区)
$expirationTime = strtotime($user['expiracao']);
$currentTime = time();
$validDuration = 15 * 60; // 15 minutos em segundos
if ($currentTime - $expirationTime > $validDuration) {
// 清理已过期记录(可选,提升数据整洁性)
$cleanup = $conn->prepare("UPDATE login SET recuperar_senha = '', expiracao = NULL WHERE id = ?");
$cleanup->execute([$user['id']]);
die('Link expirado. Por favor, solicite um novo link de recuperação.');
}
// ✅ Token válido — prosseguir para tela de redefinição de senha
// (exibir formulário, validar nova senha, etc.)
?>
? 关键注意事项:
-
时区一致性:确保 MySQL 的
time_zone与 PHP 的date_default_timezone_set()设置一致(例如均设为'America/Sao_Paulo'),否则NOW()与time()会产生偏差; -
字段类型建议:
expiracao列应定义为DATETIME或TIMESTAMP,避免使用字符串存储时间; -
安全性增强:
- Token 应为一次性(使用后立即置空):验证成功后执行
UPDATE login SET recuperar_senha='', expiracao=NULL WHERE id=?; - 建议增加
used_at时间戳字段,防止重复提交; - Token 生成应使用加密安全随机源(如
random_bytes()+bin2hex()),而非基于id和senha的password_hash()(后者可被逆向推测或碰撞);
- Token 应为一次性(使用后立即置空):验证成功后执行
-
不推荐 CREATE EVENT 的原因:
- 需要
EVENT权限(多数共享主机禁用); - 无法绑定到单条记录生命周期(EVENT 是全局调度,不适合用户级 TTL);
- 错误难以追踪,失败无日志反馈;
- 违反“验证即授权”原则,增加系统耦合。
- 需要
? 进阶优化(可选):
若需更精细的过期管理(如审计、统计),可添加 created_at(生成时间)和 expires_at(预计算的到期时间,如 DATE_ADD(NOW(), INTERVAL 15 MINUTE)),验证时直接对比 NOW() ,语义更清晰、性能更优。
综上,放弃 MySQL Event,拥抱应用层时效校验——这是更轻量、更可靠、更符合现代 Web 安全实践的解决方案。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











