首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 網頁程式設計 >> PHP 程式設計 >> PHP 綜合知識

ThinkPHP 實現郵件找回密碼:從郵件類配置到 Token 驗證的完整流程

     編輯:PHP 綜合知識

業務流程圖解

  1. 用戶輸入註冊郵箱 → 後端驗證存在性。
  2. 生成唯一 Token(含時間戳、隨機數),存入 Session/Redis,郵件發送重置鏈接。
  3. 用戶點擊鏈接 → 後端驗證 Token 有效性(未過期、未使用、匹配用戶)。
  4. 通過 → 顯示設定新密碼表單 → 提交 → 更新資料庫 → 失效 Token → 登入頁。

步驟一:引入郵件類並配置

下載 Mail.class.php (PHPMailer 輕量封裝) 放入 ThinkPHP/Lib/ORG/。
項目配置 Conf/config.php:

'MAIL_ADDRESS'   => 'noreply@example.com',   // 發件地址
'MAIL_SMTP'      => 'smtp.example.com',      // SMTP 服務器
'MAIL_LOGINNAME' => 'noreply@example.com',   // 登錄用戶名
'MAIL_PASSWORD'  => 'your_smtp_password',    // 登錄密碼
'MAIL_CHARSET'   => 'UTF-8',
'MAIL_AUTH'      => true,
'MAIL_HTML'      => true,

步驟二:發送重置郵件控制器

<?php
class MailAction extends Action {
    public function forget() {
        $email = I('post.email');
        if (!$email) $this->error('請輸入郵箱');

        $user = M('User')->where(['email' => $email])->find();
        if (!$user) $this->error('該郵箱未註冊'); // 防止用戶枚舉,實際可統一提示「若存在會發送」

        // 生成 Token:用戶ID + 時間戳 + 隨機串 -> SHA256
        $token = hash('sha256', $user['id'] . microtime(true) . random_bytes(16));
        $expire = time() + 3600; // 1 小時有效

        // 存儲到 Session(或 Redis: key=reset_token:$token, value=user_id, ttl=3600)
        session('reset_token_' . $token, ['uid' => $user['id'], 'expire' => $expire]);

        $resetUrl = U('Mail/reset', ['token' => $token], '', true); // 完整域名 URL
        $body = "<p>親愛的 {$user['username']},您申請重置密碼:</p>
                 <p><a href='$resetUrl'>$resetUrl</a></p>
                 <p>鏈接 1 小時內有效,若非本人操作請忽略。</p>";

        import('@.ORG.Mail');
        if (SendMail($email, '密碼重置請求', $body, '系統管理員')) {
            $this->success('重置郵件已發送,請查收');
        } else {
            $this->error('郵件發送失敗,請聯繫管理員');
        }
    }

    public function reset() {
        $token = I('get.token');
        $data = session('reset_token_' . $token);
        if (!$data || $data['expire'] < time()) {
            $this->error('鏈接無效或已過期');
        }
        $this->assign('token', $token);
        $this->display(); // 顯示設定新密碼表單
    }

    public function doReset() {
        $token = I('post.token');
        $pwd   = I('post.password');
        $pwd2  = I('post.password2');

        $data = session('reset_token_' . $token);
        if (!$data || $data['expire'] < time()) $this->error('Token 過期');
        if ($pwd !== $pwd2) $this->error('兩次密碼不一致');
        if (strlen($pwd) < 8) $this->error('密碼至少 8 位');

        $ok = M('User')->where(['id' => $data['uid']])->save(['password' => md5($pwd . C('PWD_SALT'))]);
        if ($ok) {
            session('reset_token_' . $token, null); // 失效 Token
            $this->success('密碼重置成功,請登入', U('Public/login'));
        } else {
            $this->error('重置失敗,請重試');
        }
    }
}

步驟三:視圖模板

Mail/forget.html

<form action="__URL__/forget" method="post">
    <input type="email" name="email" placeholder="註冊郵箱" required>
    <button type="submit">發送重置鏈接</button>
</form>

Mail/reset.html

<form action="__URL__/doReset" method="post">
    <input type="hidden" name="token" value="{$token}">
    <input type="password" name="password" placeholder="新密碼" required>
    <input type="password" name="password2" placeholder="確認密碼" required>
    <button type="submit">確定修改</button>
</form>

安全加固清單

風險對策
Token 洩露被盜用Token 僅一次性、短效期 (1h)、綁定用戶 ID、HTTPS 傳輸
用戶枚舉攻擊無論郵箱是否存在,前端統一提示「若郵箱存在,重置郵件已發送」
密碼明文存儲資料庫存 md5(password . salt) 或 password_hash() (PHP 5.5+)
CSRF 攻擊表單加 {:token} 隱藏域,控制器驗證
暴力破解 TokenToken 使用 256 位熵,配合 Rate Limit (同 IP 15 分鐘最多 3 次請求)

進階:使用 Redis 替代 Session 存儲 Token

// Redis 鍵結構
// Key:   pwd_reset:{token}
// Value: { "uid": 123, "email": "user@example.com" }
// TTL:   3600 秒

$redis = new Redis();
$redis->connect('127.0.0.1', 6379);

// 存
$redis->setex("pwd_reset:$token", 3600, json_encode(['uid' => $user['id']]));

// 取
$tokenData = json_decode($redis->get("pwd_reset:$token"), true);
if (!$tokenData) { /* 過期或不存在 */ }

// 刪
$redis->del("pwd_reset:$token");

Redis 方案支援分佈式部署、Token 可跨伺服器驗證、不佔用 Session 文件空間。

總結

ThinkPHP 郵件找回密碼的核心在於 Token 生成 → 安全存儲 → 郵件投遞 → 驗證消費 → 失效 閉環。配合 Mail.class.php 發送 HTML 郵件,使用 Session 或 Redis 存儲 Token,嚴格校驗有效期與一次性使用,即可構建安全可靠的密碼重置功能。生產環境務必啟用 SMTP SSL/TLS、配置 SPF/DKIM/DMARC 提高郵件送達率。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved