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

PHP 使用 Cookie 實作簡易登入授權機制

     編輯:PHP 相關知識

PHP 使用 Cookie 實作簡易登入授權機制

展示表單登入、密碼雜湊驗證、Session+Cookie 雙重標記、記住我功能的完整流程。

完整程式碼

<?php
session_start();

$host = 'localhost';
$user = 'root';
$pass = 'password';
$db   = 'auth_demo';

$mysqli = new mysqli($host, $user, $pass, $db);
if ($mysqli->connect_errno) die('DB連線失敗');
$mysqli->set_charset('utf8mb4');

$message = '';

// 處理登入
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
    $username = trim($_POST['username'] ?? '');
    $password = $_POST['password'] ?? '';
    $remember = isset($_POST['remember']);

    if ($username && $password) {
        // 預備語句查詢用戶
        $stmt = $mysqli->prepare('SELECT id, username, password_hash FROM users WHERE username = ?');
        $stmt->bind_param('s', $username);
        $stmt->execute();
        $user = $stmt->get_result()->fetch_assoc();
        $stmt->close();

        if ($user && password_verify($password, $user['password_hash'])) {
            // 登入成功
            $_SESSION['user_id'] = $user['id'];
            $_SESSION['username'] = $user['username'];
            $_SESSION['authenticated'] = true;

            // 記住我:設定長效 Cookie
            if ($remember) {
                $selector = bin2hex(random_bytes(16));
                $validator = bin2hex(random_bytes(32));
                $hash = hash('sha256', $validator);
                $expires = time() + 30 * 86400; // 30天

                $stmt = $mysqli->prepare('INSERT INTO remember_tokens (user_id, selector, validator_hash, expires) VALUES (?, ?, ?, FROM_UNIXTIME(?))');
                $stmt->bind_param('issi', $user['id'], $selector, $hash, $expires);
                $stmt->execute();
                $stmt->close();

                setcookie('remember', $selector . ':' . $validator, $expires, '/', '', true, true);
            }

            header('Location: dashboard.php');
            exit;
        } else {
            $message = '帳號或密碼錯誤';
        }
    } else {
        $message = '請輸入帳號密碼';
    }
}

// 自動登入檢查(每次頁面載入)
if (!isset($_SESSION['authenticated']) && isset($_COOKIE['remember'])) {
    list($selector, $validator) = explode(':', $_COOKIE['remember'], 2);
    $hash = hash('sha256', $validator);

    $stmt = $mysqli->prepare('SELECT user_id FROM remember_tokens WHERE selector = ? AND validator_hash = ? AND expires > NOW()');
    $stmt->bind_param('ss', $selector, $hash);
    $stmt->execute();
    $token = $stmt->get_result()->fetch_assoc();
    $stmt->close();

    if ($token) {
        // 取得用戶資料
        $stmt = $mysqli->prepare('SELECT id, username FROM users WHERE id = ?');
        $stmt->bind_param('i', $token['user_id']);
        $stmt->execute();
        $user = $stmt->get_result()->fetch_assoc();
        $stmt->close();

        if ($user) {
            $_SESSION['user_id'] = $user['id'];
            $_SESSION['username'] = $user['username'];
            $_SESSION['authenticated'] = true;
            // 更新 token 到期時間(滑動過期)
            $newExpires = time() + 30 * 86400;
            $stmt = $mysqli->prepare('UPDATE remember_tokens SET expires = FROM_UNIXTIME(?) WHERE selector = ?');
            $stmt->bind_param('is', $newExpires, $selector);
            $stmt->execute();
            $stmt->close();
        }
    }
}
?>
<!DOCTYPE html>
<html><head><meta charset="utf-8"><title>登入</title></head>
<body>
<h1>會員登入</h1>
<?php if ($message): ?><div style="color:red"><?= $message ?></div><?php endif; ?>
<form method="post">
    <p>帳號:<input type="text" name="username" value="<?= htmlspecialchars($_COOKIE['remember'] ? '' : ($_POST['username'] ?? '')) ?>" required></p>
    <p>密碼:<input type="password" name="password" required></p>
    <p><label><input type="checkbox" name="remember"> 記住我 (30天)</label></p>
    <button type="submit">登入</button>
</form>
</body></html>

資料表結構

CREATE TABLE users (
    id INT AUTO_INCREMENT PRIMARY KEY,
    username VARCHAR(50) NOT NULL UNIQUE,
    password_hash VARCHAR(255) NOT NULL,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

CREATE TABLE remember_tokens (
    id INT AUTO_INCREMENT PRIMARY KEY,
    user_id INT NOT NULL,
    selector VARCHAR(32) NOT NULL,
    validator_hash VARCHAR(64) NOT NULL,
    expires DATETIME NOT NULL,
    INDEX idx_selector (selector),
    FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE
);

安全關鍵點

措施說明
密碼雜湊password_hash() + password_verify(),預設 bcrypt,成本可調
預備語句所有查詢參數化,防 SQL 注入
記住我機制Selector:Validator 雙重 Token,Validator 僅存雜湊,Selector 索引查詢
Cookie 安全屬性HttpOnly、Secure、SameSite=Lax、path=/
Session 固定保護登入後 session_regenerate_id(true)
Token 滑動過期每次自動登入延長有效期,閒置 30 天失效
登出清理刪除 DB token、清除 Cookie、銷毀 Session

登出程式碼

<?php
session_start();
if (isset($_COOKIE['remember'])) {
    list($selector) = explode(':', $_COOKIE['remember'], 2);
    // 刪除 DB token
    $mysqli->prepare('DELETE FROM remember_tokens WHERE selector = ?')->bind_param('s', $selector)->execute();
    // 刪除 Cookie
    setcookie('remember', '', time() - 3600, '/', '', true, true);
}
$_SESSION = [];
session_destroy();
header('Location: login.php');
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved