本文目录导读:

我来详细说明PHP权限日志的实现方法:
基础权限日志系统
数据库表结构
CREATE TABLE permission_logs (
id INT AUTO_INCREMENT PRIMARY KEY,
user_id INT NOT NULL,
username VARCHAR(50),
action VARCHAR(50) NOT NULL,
resource VARCHAR(100),
resource_id INT,
status TINYINT(1) DEFAULT 1, -- 1成功 0失败
ip_address VARCHAR(45),
user_agent TEXT,
detail TEXT,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
INDEX idx_user_id (user_id),
INDEX idx_action (action),
INDEX idx_created_at (created_at)
);
PHP实现类
<?php
class PermissionLogger {
private $db;
private $logConfig;
public function __construct($dbConnection) {
$this->db = $dbConnection;
$this->logConfig = [
'enabled' => true,
'log_level' => 'info', // error, warning, info, debug
'retention_days' => 90,
'log_methods' => ['database', 'file'] // 支持多种存储方式
];
}
/**
* 记录权限日志
*/
public function log($userId, $action, $resource, $resourceId = null,
$status = true, $detail = null) {
try {
if (!$this->logConfig['enabled']) {
return false;
}
// 获取用户信息
$userInfo = $this->getUserInfo($userId);
$logData = [
'user_id' => $userId,
'username' => $userInfo['username'] ?? 'Unknown',
'action' => $action,
'resource' => $resource,
'resource_id' => $resourceId,
'status' => $status ? 1 : 0,
'ip_address' => $this->getClientIP(),
'user_agent' => $_SERVER['HTTP_USER_AGENT'] ?? '',
'detail' => $detail ? json_encode($detail) : null,
'created_at' => date('Y-m-d H:i:s')
];
// 保存到数据库
$this->saveToDatabase($logData);
// 保存到文件
if (in_array('file', $this->logConfig['log_methods'])) {
$this->saveToFile($logData);
}
return true;
} catch (Exception $e) {
error_log("Permission log error: " . $e->getMessage());
return false;
}
}
/**
* 保存到数据库
*/
private function saveToDatabase($data) {
$sql = "INSERT INTO permission_logs
(user_id, username, action, resource, resource_id,
status, ip_address, user_agent, detail, created_at)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)";
$stmt = $this->db->prepare($sql);
$stmt->execute([
$data['user_id'],
$data['username'],
$data['action'],
$data['resource'],
$data['resource_id'],
$data['status'],
$data['ip_address'],
$data['user_agent'],
$data['detail'],
$data['created_at']
]);
}
/**
* 保存到文件
*/
private function saveToFile($data) {
$logDir = __DIR__ . '/logs/permission/';
if (!is_dir($logDir)) {
mkdir($logDir, 0755, true);
}
$logFile = $logDir . date('Y-m-d') . '.log';
$logLine = sprintf(
"[%s] [%s] [User:%s] [Action:%s] [Resource:%s] [Status:%s] [IP:%s] %s\n",
$data['created_at'],
$data['status'] ? 'SUCCESS' : 'FAILURE',
$data['username'],
$data['action'],
$data['resource'] . ($data['resource_id'] ? "({$data['resource_id']})" : ''),
$data['status'] ? 'Allowed' : 'Denied',
$data['ip_address'],
$data['detail'] ?: ''
);
file_put_contents($logFile, $logLine, FILE_APPEND | LOCK_EX);
}
/**
* 获取客户端IP
*/
private function getClientIP() {
$ipKeys = [
'HTTP_X_FORWARDED_FOR',
'HTTP_X_REAL_IP',
'HTTP_CLIENT_IP',
'REMOTE_ADDR'
];
foreach ($ipKeys as $key) {
if (isset($_SERVER[$key])) {
$ip = $_SERVER[$key];
if (filter_var($ip, FILTER_VALIDATE_IP)) {
return $ip;
}
}
}
return '0.0.0.0';
}
/**
* 获取用户信息
*/
private function getUserInfo($userId) {
// 这里应该从用户表查询
$sql = "SELECT id, username, role FROM users WHERE id = ?";
$stmt = $this->db->prepare($sql);
$stmt->execute([$userId]);
return $stmt->fetch(PDO::FETCH_ASSOC);
}
}
权限检查与日志记录中间件
<?php
class PermissionMiddleware {
private $logger;
private $permissions;
public function __construct($db) {
$this->logger = new PermissionLogger($db);
$this->permissions = [
'admin' => ['create', 'read', 'update', 'delete'],
'editor' => ['create', 'read', 'update'],
'viewer' => ['read']
];
}
/**
* 检查权限并记录日志
*/
public function checkPermission($userId, $requiredAction, $resource) {
try {
// 获取用户角色
$userRole = $this->getUserRole($userId);
// 检查权限
$hasPermission = $this->hasPermission($userRole, $requiredAction);
// 记录权限检查日志
$this->logger->log(
$userId,
$hasPermission ? 'PERMISSION_CHECK' : 'PERMISSION_DENIED',
$resource,
null,
$hasPermission,
[
'role' => $userRole,
'required_action' => $requiredAction,
'has_permission' => $hasPermission
]
);
if (!$hasPermission) {
throw new \Exception("权限不足:需要 {$requiredAction} 权限");
}
return true;
} catch (Exception $e) {
// 记录异常
$this->logger->log(
$userId,
'PERMISSION_ERROR',
$resource,
null,
false,
['error' => $e->getMessage()]
);
throw $e;
}
}
private function getUserRole($userId) {
// 从数据库查询用户角色
$sql = "SELECT role FROM users WHERE id = ?";
$stmt = $this->db->prepare($sql);
$stmt->execute([$userId]);
return $stmt->fetchColumn();
}
private function hasPermission($role, $action) {
return isset($this->permissions[$role]) &&
in_array($action, $this->permissions[$role]);
}
}
使用示例
<?php
// 初始化
$db = new PDO('mysql:host=localhost;dbname=test', 'root', 'password');
$permissionLog = new PermissionLogger($db);
$permissionMiddleware = new PermissionMiddleware($db);
// 记录简单的权限操作
$permissionLog->log(
1, // 用户ID
'LOGIN', // 操作类型
'system', // 资源
null, // 资源ID
true, // 是否成功
['login_method' => 'password'] // 详细信息
);
// 记录文件访问权限
$permissionLog->log(
2,
'FILE_ACCESS',
'document',
123,
true,
['file_path' => '/uploads/document.pdf', 'action' => 'download']
);
// 使用中间件检查权限
try {
$permissionMiddleware->checkPermission(
$userId,
'delete',
'article'
);
// 执行删除操作
} catch (Exception $e) {
echo $e->getMessage();
}
日志管理功能
<?php
class PermissionLogManager {
private $db;
public function __construct($db) {
$this->db = $db;
}
/**
* 查询权限日志
*/
public function queryLogs($filters = [], $page = 1, $perPage = 20) {
$where = [];
$params = [];
if (!empty($filters['user_id'])) {
$where[] = "user_id = ?";
$params[] = $filters['user_id'];
}
if (!empty($filters['action'])) {
$where[] = "action = ?";
$params[] = $filters['action'];
}
if (!empty($filters['status'])) {
$where[] = "status = ?";
$params[] = $filters['status'];
}
if (!empty($filters['date_from'])) {
$where[] = "created_at >= ?";
$params[] = $filters['date_from'];
}
if (!empty($filters['date_to'])) {
$where[] = "created_at <= ?";
$params[] = $filters['date_to'];
}
$whereClause = $where ? 'WHERE ' . implode(' AND ', $where) : '';
// 计算总数
$countSql = "SELECT COUNT(*) FROM permission_logs {$whereClause}";
$countStmt = $this->db->prepare($countSql);
$countStmt->execute($params);
$total = $countStmt->fetchColumn();
// 获取分页数据
$offset = ($page - 1) * $perPage;
$sql = "SELECT * FROM permission_logs {$whereClause}
ORDER BY created_at DESC LIMIT ? OFFSET ?";
$params[] = $perPage;
$params[] = $offset;
$stmt = $this->db->prepare($sql);
$stmt->execute($params);
$logs = $stmt->fetchAll(PDO::FETCH_ASSOC);
return [
'total' => $total,
'page' => $page,
'per_page' => $perPage,
'data' => $logs
];
}
/**
* 清理过期日志
*/
public function cleanOldLogs($days = 90) {
$sql = "DELETE FROM permission_logs WHERE created_at < DATE_SUB(NOW(), INTERVAL ? DAY)";
$stmt = $this->db->prepare($sql);
return $stmt->execute([$days]);
}
/**
* 导出日志
*/
public function exportLogs($filters = []) {
$logs = $this->queryLogs($filters, 1, 1000000);
header('Content-Type: text/csv');
header('Content-Disposition: attachment; filename="permission_logs.csv"');
$output = fopen('php://output', 'w');
fputcsv($output, ['ID', 'User', 'Action', 'Resource', 'Status', 'IP', 'Time']);
foreach ($logs['data'] as $log) {
fputcsv($output, [
$log['id'],
$log['username'],
$log['action'],
$log['resource'] . ' (' . $log['resource_id'] . ')',
$log['status'] ? 'Success' : 'Failed',
$log['ip_address'],
$log['created_at']
]);
}
fclose($output);
exit;
}
}
性能优化建议
- 使用消息队列:对于高并发场景,将日志写入内存队列
- 定期归档:将旧日志归档到单独的表或文件
- 索引优化:在常用查询字段上建立索引
- 缓存热点数据:使用Redis缓存最近的日志
安全考虑
- 对敏感信息进行脱敏处理
- 日志文件权限设置为600
- 限制日志查询的访问权限
- 对日志API进行速率限制
这个系统可以帮助你全面记录和管理权限相关的操作,便于审计和问题排查。