我将为您提供一个完整的PHP人脸识别认证系统实现方案,这个系统将使用百度AI开放平台提供的人脸识别API。

完整的人脸识别认证系统
系统架构
项目结构:
├── config/
│ └── config.php # 配置文件
├── includes/
│ ├── FaceAuth.php # 人脸认证核心类
│ ├── Database.php # 数据库操作类
│ └── ImageUpload.php # 图片上传处理类
├── uploads/ # 上传图片目录
├── register.php # 人脸注册页面
├── login.php # 人脸登录页面
├── auth_callback.php # 认证回调处理
└── database.sql # 数据库结构
数据库结构
-- database.sql
CREATE DATABASE IF NOT EXISTS face_auth_system;
USE face_auth_system;
-- 用户表
CREATE TABLE users (
id INT PRIMARY KEY AUTO_INCREMENT,
username VARCHAR(50) UNIQUE NOT NULL,
email VARCHAR(100) UNIQUE NOT NULL,
face_token VARCHAR(100) UNIQUE NOT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
last_login TIMESTAMP NULL
);
-- 认证记录表
CREATE TABLE auth_logs (
id INT PRIMARY KEY AUTO_INCREMENT,
user_id INT,
auth_type ENUM('register', 'login', 'verify') NOT NULL,
result ENUM('success', 'failed') NOT NULL,
score FLOAT,
ip_address VARCHAR(45),
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (user_id) REFERENCES users(id)
);
配置文件
<?php
// config/config.php
// 数据库配置
define('DB_HOST', 'localhost');
define('DB_NAME', 'face_auth_system');
define('DB_USER', 'root');
define('DB_PASS', '');
// 百度AI配置
define('BAIDU_APP_ID', '你的App ID');
define('BAIDU_API_KEY', '你的API Key');
define('BAIDU_SECRET_KEY', '你的Secret Key');
define('BAIDU_ACCESS_TOKEN_URL', 'https://aip.baidubce.com/oauth/2.0/token');
define('BAIDU_GROUP_ID', 'your_face_group');
// 系统配置
define('FACE_AUTH_THRESHOLD', 80); // 人脸认证准确率阈值
define('MAX_IMAGE_SIZE', 10 * 1024 * 1024); // 10MB
// 获取百度AI Access Token
function getBaiduAccessToken() {
$url = BAIDU_ACCESS_TOKEN_URL . '?grant_type=client_credentials&client_id=' .
BAIDU_API_KEY . '&client_secret=' . BAIDU_SECRET_KEY;
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$response = curl_exec($ch);
curl_close($ch);
$data = json_decode($response, true);
return $data['access_token'];
}
?>
核心类 - 人脸认证
<?php
// includes/FaceAuth.php
class FaceAuth {
private $accessToken;
private $appId;
private $apiUrl;
public function __construct() {
$this->appId = BAIDU_APP_ID;
$this->accessToken = getBaiduAccessToken();
$this->apiUrl = 'https://aip.baidubce.com/rest/2.0/face/v3/';
}
/**
* 人脸注册
* @param string $imageBase64 - 人脸图片Base64编码
* @param string $userId - 用户ID
* @return array - 返回face_token等信息
*/
public function faceRegister($imageBase64, $userId) {
$url = $this->apiUrl . 'face/add?access_token=' . $this->accessToken;
$params = [
'image' => $imageBase64,
'image_type' => 'BASE64',
'group_id' => BAIDU_GROUP_ID,
'user_id' => $userId,
'user_info' => 'User registration at ' . date('Y-m-d H:i:s')
];
$result = $this->curlPost($url, $params);
return $result;
}
/**
* 人脸搜索(认证登录)
* @param string $imageBase64 - 待认证人脸图片
* @return array - 返回匹配结果
*/
public function faceSearch($imageBase64) {
$url = $this->apiUrl . 'search?access_token=' . $this->accessToken;
$params = [
'image' => $imageBase64,
'image_type' => 'BASE64',
'group_id_list' => BAIDU_GROUP_ID,
'quality_control' => 'NORMAL',
'liveness_control' => 'NONE'
];
$result = $this->curlPost($url, $params);
return $result;
}
/**
* 人脸比对
* @param string $image1 - 第一张人脸图
* @param string $image2 - 第二张人脸图
* @return array - 返回相似度分数
*/
public function faceCompare($image1, $image2) {
$url = $this->apiUrl . 'match?access_token=' . $this->accessToken;
$params = [
[
'image' => $image1,
'image_type' => 'BASE64'
],
[
'image' => $image2,
'image_type' => 'BASE64'
]
];
$result = $this->curlPost($url, $params);
return $result;
}
/**
* 检测人脸质量
* @param string $imageBase64 - 人脸图片
* @return array - 返回人脸质量评估结果
*/
public function faceDetect($imageBase64) {
$url = $this->apiUrl . 'detect?access_token=' . $this->accessToken;
$params = [
'image' => $imageBase64,
'image_type' => 'BASE64',
'face_field' => 'quality,angle,beauty,age,gender'
];
$result = $this->curlPost($url, $params);
return $result;
}
/**
* 更新用户人脸
* @param string $imageBase64 - 新的人脸图片
* @param string $faceToken - 原人脸token
* @param string $userId - 用户ID
* @return array
*/
public function faceUpdate($imageBase64, $faceToken, $userId) {
$url = $this->apiUrl . 'face/update?access_token=' . $this->accessToken;
$params = [
'image' => $imageBase64,
'image_type' => 'BASE64',
'group_id' => BAIDU_GROUP_ID,
'user_id' => $userId,
'face_token' => $faceToken
];
$result = $this->curlPost($url, $params);
return $result;
}
/**
* 删除用户人脸
* @param string $faceToken - 人脸token
* @param string $userId - 用户ID
* @return array
*/
public function faceDelete($faceToken, $userId) {
$url = $this->apiUrl . 'face/delete?access_token=' . $this->accessToken;
$params = [
'face_token' => $faceToken,
'group_id' => BAIDU_GROUP_ID,
'user_id' => $userId
];
$result = $this->curlPost($url, $params);
return $result;
}
/**
* 获取用户信息
* @param string $userId - 用户ID
* @return array
*/
public function getUserInfo($userId) {
$url = $this->apiUrl . 'user/get?access_token=' . $this->accessToken;
$params = [
'group_id' => BAIDU_GROUP_ID,
'user_id' => $userId
];
$result = $this->curlPost($url, $params);
return $result;
}
/**
* 人脸活体检测
* @param string $imageBase64 - 人脸图片
* @param string $faceFields - 需要返回的属性
* @return array
*/
public function faceLiveness($imageBase64, $faceFields = 'quality,faceliveness') {
$url = $this->apiUrl . 'liveness?access_token=' . $this->accessToken;
$params = [
'image' => $imageBase64,
'image_type' => 'BASE64',
'face_field' => $faceFields
];
$result = $this->curlPost($url, $params);
return $result;
}
private function curlPost($url, $data) {
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($data));
curl_setopt($ch, CURLOPT_HTTPHEADER, [
'Content-Type: application/x-www-form-urlencoded'
]);
$response = curl_exec($ch);
curl_close($ch);
return json_decode($response, true);
}
/**
* 验证人脸认证结果
* @param array $result - 百度API返回结果
* @param float $threshold - 准确率阈值
* @return array - 认证结果
*/
public function validateAuthResult($result, $threshold = null) {
if ($threshold === null) {
$threshold = FACE_AUTH_THRESHOLD;
}
if (isset($result['error_code']) && $result['error_code'] !== 0) {
return [
'success' => false,
'error' => $result['error_msg']
];
}
if (isset($result['result']['user_list'][0])) {
$userInfo = $result['result']['user_list'][0];
$score = $userInfo['score'];
if ($score >= $threshold) {
return [
'success' => true,
'score' => $score,
'user_id' => $userInfo['user_id'],
'face_token' => $userInfo['face_token']
];
} else {
return [
'success' => false,
'error' => '认证准确率不足,当前为:' . $score . '%,需要达到' . $threshold . '%以上',
'score' => $score
];
}
}
return [
'success' => false,
'error' => '未找到匹配的人脸信息'
];
}
}
?>
数据库操作类
<?php
// includes/Database.php
class Database {
private $host;
private $dbName;
private $username;
private $password;
private $connection;
private static $instance = null;
private function __construct() {
$this->host = DB_HOST;
$this->dbName = DB_NAME;
$this->username = DB_USER;
$this->password = DB_PASS;
$this->connect();
}
public static function getInstance() {
if (self::$instance === null) {
self::$instance = new Database();
}
return self::$instance;
}
private function connect() {
try {
$dsn = "mysql:host={$this->host};dbname={$this->dbName};charset=utf8mb4";
$this->connection = new PDO($dsn, $this->username, $this->password);
$this->connection->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
} catch (PDOException $e) {
die("数据库连接失败: " . $e->getMessage());
}
}
public function getConnection() {
return $this->connection;
}
public function insertUser($username, $email, $faceToken) {
$sql = "INSERT INTO users (username, email, face_token) VALUES (?, ?, ?)";
$stmt = $this->connection->prepare($sql);
$result = $stmt->execute([$username, $email, $faceToken]);
return $result ? $this->connection->lastInsertId() : false;
}
public function getUserByFaceToken($faceToken) {
$sql = "SELECT * FROM users WHERE face_token = ?";
$stmt = $this->connection->prepare($sql);
$stmt->execute([$faceToken]);
return $stmt->fetch(PDO::FETCH_ASSOC);
}
public function getUserByUsername($username) {
$sql = "SELECT * FROM users WHERE username = ?";
$stmt = $this->connection->prepare($sql);
$stmt->execute([$username]);
return $stmt->fetch(PDO::FETCH_ASSOC);
}
public function logAuthAttempt($userId, $authType, $result, $score = null) {
$ipAddress = $_SERVER['REMOTE_ADDR'];
$sql = "INSERT INTO auth_logs (user_id, auth_type, result, score, ip_address)
VALUES (?, ?, ?, ?, ?)";
$stmt = $this->connection->prepare($sql);
return $stmt->execute([$userId, $authType, $result, $score, $ipAddress]);
}
}
?>
注册页面
<?php
// register.php
session_start();
require_once 'config/config.php';
require_once 'includes/Database.php';
require_once 'includes/FaceAuth.php';
$db = Database::getInstance()->getConnection();
$faceAuth = new FaceAuth();
$errors = [];
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
// 获取表单数据
$username = trim($_POST['username']);
$email = trim($_POST['email']);
$password = $_POST['password'];
$confirmPassword = $_POST['confirm_password'];
// 检查用户名和邮箱是否已存在
$stmt = $db->prepare("SELECT id FROM users WHERE username = ? OR email = ?");
$stmt->execute([$username, $email]);
if ($stmt->fetch()) {
$errors[] = "用户名或邮箱已被注册";
}
// 验证密码
if ($password !== $confirmPassword) {
$errors[] = "两次输入密码不一致";
}
// 处理人脸图片上传
if (isset($_FILES['face_image']) && $_FILES['face_image']['error'] === UPLOAD_ERR_OK) {
try {
// 验证图片
if ($_FILES['face_image']['size'] > MAX_IMAGE_SIZE) {
throw new Exception("图片大小不能超过10MB");
}
// 转为Base64
$imageContent = file_get_contents($_FILES['face_image']['tmp_name']);
$base64Image = base64_encode($imageContent);
// 进行人脸检测,确保图片中有人脸
$detectResult = $faceAuth->faceDetect($base64Image);
if (isset($detectResult['error_code']) && $detectResult['error_code'] !== 0) {
throw new Exception("人脸检测失败: " . $detectResult['error_msg']);
}
if ($detectResult['result']['face_num'] === 0) {
throw new Exception("图片中没有检测到人脸");
}
// 检查人脸质量
$faceQuality = $detectResult['result']['face_list'][0]['quality'];
if ($faceQuality['blur'] > 0.8 || $faceQuality['illumination'] < 0.5) {
throw new Exception("人脸图片质量不佳,请更换照片");
}
// 生成唯一用户ID
$userId = md5(uniqid() . time());
// 注册人脸
$registerResult = $faceAuth->faceRegister($base64Image, $userId);
if (isset($registerResult['error_code']) && $registerResult['error_code'] !== 0) {
throw new Exception("人脸注册失败: " . $registerResult['error_msg']);
}
$faceToken = $registerResult['result']['face_token'];
// 保存用户信息
$hashedPassword = password_hash($password, PASSWORD_DEFAULT);
$sql = "INSERT INTO users (username, email, face_token, user_id) VALUES (?, ?, ?, ?)";
$stmt = $db->prepare($sql);
$stmt->execute([$username, $email, $faceToken, $userId]);
// 记录注册日志
$db->prepare("INSERT INTO auth_logs (user_id, auth_type, result) VALUES (?, 'register', 'success')")
->execute([$userId]);
$_SESSION['success'] = "注册成功!请使用人脸识别登录";
header('Location: login.php');
exit();
} catch (Exception $e) {
$errors[] = $e->getMessage();
}
} else {
$errors[] = "请上传人脸图片";
}
}
?>
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">人脸识别注册</title>
<style>
.container { max-width: 600px; margin: 50px auto; padding: 20px; }
.form-group { margin-bottom: 20px; }
.form-group label { display: block; margin-bottom: 5px; }
.form-group input { width: 100%; padding: 8px; border: 1px solid #ddd; border-radius: 4px; }
.error { color: red; margin-bottom: 10px; }
.success { color: green; margin-bottom: 10px; }
#camera-preview { width: 300px; height: 300px; margin: 10px 0; }
</style>
</head>
<body>
<div class="container">
<h2>人脸识别注册</h2>
<?php if (!empty($errors)): ?>
<div class="error">
<?php foreach ($errors as $error): ?>
<p><?php echo htmlspecialchars($error); ?></p>
<?php endforeach; ?>
</div>
<?php endif; ?>
<?php if (isset($_SESSION['success'])): ?>
<div class="success"><?php echo $_SESSION['success']; ?></div>
<?php endif; ?>
<form method="POST" enctype="multipart/form-data">
<div class="form-group">
<label>用户名</label>
<input type="text" name="username" required>
</div>
<div class="form-group">
<label>邮箱</label>
<input type="email" name="email" required>
</div>
<div class="form-group">
<label>密码</label>
<input type="password" name="password" required>
</div>
<div class="form-group">
<label>确认密码</label>
<input type="password" name="confirm_password" required>
</div>
<div class="form-group">
<label>人脸图片</label>
<input type="file" name="face_image" accept="image/*" capture="user" required>
</div>
<div class="form-group">
<label>拍照或上传照片</label>
<button type="button" id="camera-button">打开摄像头</button>
<video id="camera-preview" autoplay playsinline style="display:none;"></video>
<canvas id="face-capture" style="display:none;"></canvas>
</div>
<button type="submit">注册</button>
</form>
<p>已有账号?<a href="login.php">登录</a></p>
</div>
<script>
// 摄像头拍照功能
const cameraButton = document.getElementById('camera-button');
const preview = document.getElementById('camera-preview');
const canvas = document.getElementById('face-capture');
const fileInput = document.querySelector('input[name="face_image"]');
cameraButton.addEventListener('click', async () => {
try {
const stream = await navigator.mediaDevices.getUserMedia({ video: true });
preview.srcObject = stream;
preview.style.display = 'block';
// 3秒后自动拍照
setTimeout(() => {
canvas.width = preview.videoWidth;
canvas.height = preview.videoHeight;
canvas.getContext('2d').drawImage(preview, 0, 0);
// 停止摄像头
stream.getTracks().forEach(track => track.stop());
preview.style.display = 'none';
// 将canvas转为文件
canvas.toBlob(blob => {
const file = new File([blob], 'face.png', { type: 'image/png' });
const dt = new DataTransfer();
dt.items.add(file);
fileInput.files = dt.files;
}, 'image/png');
}, 3000);
} catch (error) {
console.error('摄像头访问失败:', error);
alert('无法访问摄像头,请使用文件上传');
}
});
</script>
</body>
</html>
登录认证页面
<?php
// login.php
session_start();
require_once 'config/config.php';
require_once 'includes/Database.php';
require_once 'includes/FaceAuth.php';
$db = Database::getInstance()->getConnection();
$faceAuth = new FaceAuth();
$errors = [];
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
if (isset($_POST['face_data'])) {
// 人脸识别登录
$base64Image = $_POST['face_data'];
// 执行人脸搜索
$searchResult = $faceAuth->faceSearch($base64Image);
// 验证认证结果
$authResult = $faceAuth->validateAuthResult($searchResult);
if ($authResult['success']) {
// 获取用户信息
$stmt = $db->prepare("SELECT * FROM users WHERE user_id = ?");
$stmt->execute([$authResult['user_id']]);
$user = $stmt->fetch(PDO::FETCH_ASSOC);
if ($user) {
// 更新最后登录时间
$db->prepare("UPDATE users SET last_login = NOW() WHERE id = ?")
->execute([$user['id']]);
// 记录认证日志
$db->prepare("INSERT INTO auth_logs (user_id, auth_type, result, score)
VALUES (?, 'login', 'success', ?)")
->execute([$user['id'], $authResult['score']]);
// 设置会话
$_SESSION['user_id'] = $user['id'];
$_SESSION['username'] = $user['username'];
$_SESSION['face_auth'] = true;
header('Location: dashboard.php');
exit();
}
} else {
$errors[] = $authResult['error'];
}
} else {
$errors[] = "请进行人脸识别或输入密码";
}
}
?>
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">人脸识别登录</title>
<style>
.container { max-width: 600px; margin: 50px auto; padding: 20px; }
#camera { width: 100%; max-width: 400px; height: 300px; margin: 10px 0; }
.btn { padding: 10px 20px; margin: 5px; }
.preview { width: 300px; height: 300px; margin: 10px 0; }
.error { color: red; margin-bottom: 10px; }
</style>
</head>
<body>
<div class="container">
<h2>人脸识别登录</h2>
<?php if (!empty($errors)): ?>
<div class="error">
<?php foreach ($errors as $error): ?>
<p><?php echo htmlspecialchars($error); ?></p>
<?php endforeach; ?>
</div>
<?php endif; ?>
<div id="camera">
<video id="video" width="300" height="300" autoplay playsinline></video>
<canvas id="canvas" width="300" height="300" style="display:none;"></canvas>
</div>
<button id="start-camera" class="btn">开启摄像头</button>
<button id="capture-face" class="btn">拍照识别</button>
<form method="POST" id="login-form">
<input type="hidden" name="face_data" id="face-data">
</form>
<!-- 或者使用文件上传方式 -->
<hr>
<h3>或者上传照片</h3>
<form method="POST" enctype="multipart/form-data">
<input type="file" name="face_image" accept="image/*" capture="user">
<button type="submit" class="btn">上传识别</button>
</form>
<p>还没有账号?<a href="register.php">注册</a></p>
</div>
<script>
let stream = null;
const video = document.getElementById('video');
const canvas = document.getElementById('canvas');
document.getElementById('start-camera').addEventListener('click', async () => {
try {
stream = await navigator.mediaDevices.getUserMedia({ video: true });
video.srcObject = stream;
video.style.display = 'block';
} catch (error) {
console.error('摄像头错误:', error);
alert('无法访问摄像头');
}
});
document.getElementById('capture-face').addEventListener('click', () => {
canvas.getContext('2d').drawImage(video, 0, 0, 300, 300);
const dataUrl = canvas.toDataURL('image/jpeg', 0.9);
// 移除data:image/jpeg;base64,前缀
const base64 = dataUrl.split(',')[1];
document.getElementById('face-data').value = base64;
document.getElementById('login-form').submit();
});
// 文件上传方式
document.querySelector('input[name="face_image"]').addEventListener('change', function() {
if (this.files.length > 0) {
this.form.submit();
}
});
</script>
</body>
</html>
认证回调处理
<?php
// auth_callback.php
require_once 'config/config.php';
require_once 'includes/Database.php';
require_once 'includes/FaceAuth.php';
session_start();
header('Content-Type: application/json');
$db = Database::getInstance()->getConnection();
$faceAuth = new FaceAuth();
if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
echo json_encode(['success' => false, 'message' => '无效请求']);
exit();
}
try {
// 获取请求类型
$action = $_POST['action'] ?? 'search';
switch ($action) {
case 'search':
// 人脸搜索认证
$imageBase64 = $_POST['image_base64'] ?? '';
if (empty($imageBase64)) {
throw new Exception('缺少图片数据');
}
$result = $faceAuth->faceSearch($imageBase64);
$authResult = $faceAuth->validateAuthResult($result);
if ($authResult['success']) {
// 获取用户信息
$stmt = $db->prepare("SELECT * FROM users WHERE user_id = ?");
$stmt->execute([$authResult['user_id']]);
$user = $stmt->fetch(PDO::FETCH_ASSOC);
if ($user) {
// 更新最后登录时间
$db->prepare("UPDATE users SET last_login = NOW() WHERE id = ?")
->execute([$user['id']]);
// 记录日志
$db->prepare("INSERT INTO auth_logs (user_id, auth_type, result, score, ip_address)
VALUES (?, 'login', 'success', ?, ?)")
->execute([$user['id'], $authResult['score'], $_SERVER['REMOTE_ADDR']]);
// 创建会话
$_SESSION['user_id'] = $user['id'];
$_SESSION['username'] = $user['username'];
$_SESSION['face_auth'] = true;
echo json_encode([
'success' => true,
'message' => '人脸识别成功',
'score' => $authResult['score'],
'user' => [
'id' => $user['id'],
'username' => $user['username'],
'email' => $user['email']
]
]);
} else {
throw new Exception('用户不存在');
}
} else {
// 记录失败日志
$db->prepare("INSERT INTO auth_logs (auth_type, result, score, ip_address)
VALUES ('login', 'failed', ?, ?)")
->execute([$authResult['score'] ?? 0, $_SERVER['REMOTE_ADDR']]);
throw new Exception($authResult['error']);
}
break;
case 'detect':
// 人脸检测
$imageBase64 = $_POST['image_base64'] ?? '';
if (empty($imageBase64)) {
throw new Exception('缺少图片数据');
}
$result = $faceAuth->faceDetect($imageBase64);
echo json_encode($result);
break;
case 'compare':
// 人脸比对
$image1 = $_POST['image1'] ?? '';
$image2 = $_POST['image2'] ?? '';
if (empty($image1) || empty($image2)) {
throw new Exception('缺少比对图片数据');
}
$result = $faceAuth->faceCompare($image1, $image2);
echo json_encode($result);
break;
default:
throw new Exception('无效操作类型');
}
} catch (Exception $e) {
echo json_encode([
'success' => false,
'message' => $e->getMessage()
]);
}
?>
用户仪表盘页面
<?php
// dashboard.php
session_start();
// 检查认证状态
if (!isset($_SESSION['user_id'])) {
header('Location: login.php');
exit();
}
require_once 'config/config.php';
require_once 'includes/Database.php';
$db = Database::getInstance()->getConnection();
// 获取用户信息
$stmt = $db->prepare("SELECT * FROM users WHERE id = ?");
$stmt->execute([$_SESSION['user_id']]);
$user = $stmt->fetch(PDO::FETCH_ASSOC);
if (!$user) {
session_destroy();
header('Location: login.php');
exit();
}
// 获取认证日志
$stmt = $db->prepare("SELECT * FROM auth_logs WHERE user_id = ? ORDER BY created_at DESC LIMIT 10");
$stmt->execute([$_SESSION['user_id']]);
$logs = $stmt->fetchAll(PDO::FETCH_ASSOC);
?>
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">用户仪表盘</title>
<style>
.container { max-width: 800px; margin: 50px auto; padding: 20px; }
.user-info { background: #f5f5f5; padding: 20px; border-radius: 5px; }
.logs { margin-top: 30px; }
table { width: 100%; border-collapse: collapse; }
th, td { padding: 10px; border: 1px solid #ddd; text-align: left; }
.logout { float: right; }
</style>
</head>
<body>
<div class="container">
<div class="user-info">
<h2>欢迎, <?php echo htmlspecialchars($user['username']); ?>!</h2>
<p>邮箱: <?php echo htmlspecialchars($user['email']); ?></p>
<p>注册时间: <?php echo $user['created_at']; ?></p>
<p>最后登录: <?php echo $user['last_login']; ?></p>
<form method="POST" action="logout.php">
<button type="submit" class="logout">退出登录</button>
</form>
</div>
<div class="logs">
<h3>最近认证记录</h3>
<table>
<thead>
<tr>
<th>时间</th>
<th>类型</th>
<th>结果</th>
<th>准确率</th>
<th>IP地址</th>
</tr>
</thead>
<tbody>
<?php foreach ($logs as $log): ?>
<tr>
<td><?php echo $log['created_at']; ?></td>
<td><?php echo $log['auth_type']; ?></td>
<td><?php echo $log['result']; ?></td>
<td><?php echo $log['score'] ? number_format($log['score'], 2) . '%' : '-'; ?></td>
<td><?php echo $log['ip_address']; ?></td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
</div>
</div>
</body>
</html>
认证验证中间件
<?php
// includes/AuthMiddleware.php
class AuthMiddleware {
private $db;
public function __construct() {
$this->db = Database::getInstance()->getConnection();
}
/**
* 会话认证令牌验证
*/
public function validateSession() {
if (!isset($_SESSION['user_id'])) {
header('Location: login.php');
exit();
}
// 验证会话是否有效
$token = $_SESSION['auth_token'] ?? null;
if (!$token) {
$this->logout();
header('Location: login.php');
exit();
}
}
/**
* 生成认证令牌
*/
public function generateAuthToken($userId) {
$token = bin2hex(random_bytes(32));
$sql = "INSERT INTO auth_tokens (user_id, token, expires_at) VALUES (?, ?, DATE_ADD(NOW(), INTERVAL 1 HOUR))";
$stmt = $this->db->prepare($sql);
$stmt->execute([$userId, $token]);
return $token;
}
/**
* 验证认证令牌
*/
public function validateAuthToken($token, $userId = null) {
$sql = "SELECT * FROM auth_tokens WHERE token = ? AND expires_at > NOW()";
if ($userId) {
$sql .= " AND user_id = ?";
}
$stmt = $this->db->prepare($sql);
$stmt->execute($userId ? [$token, $userId] : [$token]);
$result = $stmt->fetch(PDO::FETCH_ASSOC);
return $result ? true : false;
}
/**
* 双因素认证检查
*/
public function checkTwoFactor($userId) {
版权声明:NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播