# PHP如何實現七天自動登錄
## 前言
在Web開發中,用戶登錄狀態的持久化是一個常見需求。"記住我"(Remember Me)功能可以讓用戶在關閉瀏覽器后仍保持登錄狀態,避免重復輸入賬號密碼。本文將詳細介紹如何使用PHP實現七天自動登錄功能,涵蓋Cookie機制、安全策略和完整代碼實現。
---
## 一、自動登錄的核心原理
### 1.1 基于Cookie的持久化認證
自動登錄功能主要依賴瀏覽器Cookie實現,其工作流程如下:
1. 用戶首次登錄時勾選"記住我"
2. 服務器生成唯一令牌(Token)并存入數據庫
3. 將令牌通過Cookie發送到客戶端
4. 下次訪問時,服務器驗證Cookie中的令牌
### 1.2 安全三要素
- **隨機令牌**:使用`random_bytes()`或`openssl_random_pseudo_bytes()`生成
- **有限有效期**:設置7天過期時間
- **單端使用**:一個令牌僅允許在一臺設備使用
---
## 二、數據庫設計
### 2.1 用戶表結構
```sql
CREATE TABLE `users` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`username` varchar(50) NOT NULL,
`password` varchar(255) NOT NULL,
PRIMARY KEY (`id`)
);
CREATE TABLE `auth_tokens` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`user_id` int(11) NOT NULL,
`token` varchar(64) NOT NULL,
`expires_at` datetime NOT NULL,
`user_agent` varchar(255) DEFAULT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `token` (`token`)
);
// login.php
session_start();
require 'db.php';
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$username = $_POST['username'];
$password = $_POST['password'];
$remember = isset($_POST['remember']);
$stmt = $pdo->prepare("SELECT * FROM users WHERE username = ?");
$stmt->execute([$username]);
$user = $stmt->fetch();
if ($user && password_verify($password, $user['password'])) {
$_SESSION['user_id'] = $user['id'];
if ($remember) {
// 生成令牌
$token = bin2hex(random_bytes(32));
$expires = date('Y-m-d H:i:s', strtotime('+7 days'));
// 存儲令牌
$stmt = $pdo->prepare("
INSERT INTO auth_tokens
(user_id, token, expires_at, user_agent)
VALUES (?, ?, ?, ?)
");
$stmt->execute([
$user['id'],
$token,
$expires,
$_SERVER['HTTP_USER_AGENT']
]);
// 設置Cookie(7天有效期)
setcookie(
'remember_token',
$token,
time() + 60 * 60 * 24 * 7,
'/',
'',
true, // 僅HTTPS
true // HttpOnly
);
}
header('Location: /dashboard.php');
exit;
}
}
// auth.php
session_start();
require 'db.php';
function checkAutoLogin() {
global $pdo;
if (empty($_SESSION['user_id']) && !empty($_COOKIE['remember_token'])) {
$token = $_COOKIE['remember_token'];
$stmt = $pdo->prepare("
SELECT u.* FROM auth_tokens t
JOIN users u ON t.user_id = u.id
WHERE t.token = ?
AND t.expires_at > NOW()
AND t.user_agent = ?
");
$stmt->execute([$token, $_SERVER['HTTP_USER_AGENT']]);
$user = $stmt->fetch();
if ($user) {
$_SESSION['user_id'] = $user['id'];
// 刷新令牌有效期(可選)
$newExpires = date('Y-m-d H:i:s', strtotime('+7 days'));
$pdo->prepare("UPDATE auth_tokens SET expires_at = ? WHERE token = ?")
->execute([$newExpires, $token]);
setcookie(
'remember_token',
$token,
time() + 60 * 60 * 24 * 7,
'/',
'',
true,
true
);
} else {
// 無效令牌則清除Cookie
setcookie('remember_token', '', time() - 3600, '/');
}
}
}
// 在需要驗證的頁面調用
checkAutoLogin();
// logout.php
session_start();
require 'db.php';
if (!empty($_SESSION['user_id'])) {
// 清除數據庫令牌
if (!empty($_COOKIE['remember_token'])) {
$pdo->prepare("DELETE FROM auth_tokens WHERE token = ?")
->execute([$_COOKIE['remember_token']]);
}
// 清除Session和Cookie
session_destroy();
setcookie('remember_token', '', time() - 3600, '/');
}
header('Location: /login.php');
// 生成CSRF令牌
if (empty($_SESSION['csrf_token'])) {
$_SESSION['csrf_token'] = bin2hex(random_bytes(32));
}
// 在表單中隱藏域
<input type="hidden" name="csrf_token" value="<?= $_SESSION['csrf_token'] ?>">
// 驗證CSRF
if ($_POST['csrf_token'] !== $_SESSION['csrf_token']) {
die('CSRF驗證失敗');
}
創建定時任務(Cron Job):
0 3 * * * php /path/to/clean_tokens.php
// clean_tokens.php
$pdo->exec("DELETE FROM auth_tokens WHERE expires_at < NOW()");
// 存儲登錄時的完整User-Agent
$userAgent = $_SERVER['HTTP_USER_AGENT'];
// 驗證時嚴格匹配
AND t.user_agent = ?
強制HTTPS:防止令牌被竊聽
ini_set('session.cookie_secure', 1);
令牌輪換:每次驗證后生成新令牌
// 驗證成功后
$newToken = bin2hex(random_bytes(32));
登錄日志:記錄所有登錄行為
CREATE TABLE `login_logs` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`user_id` int(11) NOT NULL,
`ip_address` varchar(45) NOT NULL,
`login_at` datetime NOT NULL,
PRIMARY KEY (`id`)
);
異常檢測:同一賬號多地登錄提醒
通過本文介紹的方法,您可以實現安全的七天自動登錄功能。關鍵點在于: - 使用高強度的隨機令牌 - 嚴格的數據庫驗證 - 完善的過期機制 - 多層次的安全防護
實際項目中還需根據具體需求進行調整,建議結合框架(如Laravel的Auth
組件)來實現更完善的身份認證系統。
“`
注:本文代碼示例約1200字,加上技術說明后總字數約1900字。實際使用時可根據需要調整細節,如添加更多錯誤處理或前端界面示例。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。