PHP实战:从零到一构建企业级应用(四)

简介: 教程来源:https://htnus.cn/category/software-apps.html 本节详解PHP应用安全与性能优化:含认证/权限中间件(Token校验、RBAC控制)、多重安全防护(XSS/CSRF/SQL注入防御、速率限制、安全头设置),以及Redis缓存服务与数据库查询缓存,全面提升系统安全性与响应性能。

第七部分:中间件与安全

7.1 认证中间件

// app/Middleware/AuthMiddleware.php
<?php
namespace App\Middleware;

use App\Services\AuthService;

class AuthMiddleware
{
    private AuthService $auth;

    public function __construct()
    {
        $this->auth = new AuthService();
    }

    public function handle(): void
    {
        // 从请求头获取Token
        $headers = getallheaders();
        $token = $headers['Authorization'] ?? $_SESSION['api_token'] ?? null;

        if (!$token) {
            $this->unauthorized('未提供认证Token');
        }

        $token = str_replace('Bearer ', '', $token);
        $user = $this->auth->authenticateByToken($token);

        if (!$user) {
            $this->unauthorized('Token无效或已过期');
        }

        if ($user->status != 1) {
            $this->unauthorized('账号已被禁用');
        }

        $this->auth->setUser($user);
    }

    private function unauthorized(string $message): void
    {
        http_response_code(401);
        header('Content-Type: application/json');
        echo json_encode([
            'code' => 401,
            'message' => $message,
            'timestamp' => time()
        ]);
        exit;
    }
}

7.2 权限中间件

// app/Middleware/PermissionMiddleware.php
<?php
namespace App\Middleware;

use App\Services\AuthService;

class PermissionMiddleware
{
    private AuthService $auth;

    public function __construct()
    {
        $this->auth = new AuthService();
    }

    public function handle(string $permission = null): void
    {
        // 从路由中获取需要的权限
        // 实际项目中可以从配置或注解中获取
        $requiredPermission = $this->getRequiredPermission();

        if (!$this->auth->can($requiredPermission)) {
            $this->forbidden('无权限访问');
        }
    }

    private function getRequiredPermission(): string
    {
        // 根据当前请求的URI和方法确定所需权限
        $uri = $_SERVER['REQUEST_URI'];
        $method = $_SERVER['REQUEST_METHOD'];

        $permissionMap = [
            'GET' => [
                '#/api/users$#' => 'user.view',
                '#/api/users/\d+$#' => 'user.view',
            ],
            'POST' => [
                '#/api/users$#' => 'user.create',
            ],
            'PUT' => [
                '#/api/users/\d+$#' => 'user.edit',
            ],
            'DELETE' => [
                '#/api/users/\d+$#' => 'user.delete',
            ],
        ];

        foreach ($permissionMap[$method] ?? [] as $pattern => $permission) {
            if (preg_match($pattern, $uri)) {
                return $permission;
            }
        }

        return '';
    }

    private function forbidden(string $message): void
    {
        http_response_code(403);
        header('Content-Type: application/json');
        echo json_encode([
            'code' => 403,
            'message' => $message,
            'timestamp' => time()
        ]);
        exit;
    }
}

7.3 安全防护

// app/Security/SecurityManager.php
<?php
namespace App\Security;

class SecurityManager
{
    /**
     * 防止SQL注入(使用PDO预处理语句即可)
     */

    /**
     * 防止XSS攻击
     */
    public static function sanitizeInput(string $input): string
    {
        return htmlspecialchars($input, ENT_QUOTES | ENT_HTML5, 'UTF-8');
    }

    /**
     * 防止CSRF攻击
     */
    public static function generateCsrfToken(): string
    {
        if (empty($_SESSION['csrf_token'])) {
            $_SESSION['csrf_token'] = bin2hex(random_bytes(32));
        }
        return $_SESSION['csrf_token'];
    }

    public static function verifyCsrfToken(string $token): bool
    {
        return isset($_SESSION['csrf_token']) && hash_equals($_SESSION['csrf_token'], $token);
    }

    /**
     * 限制请求频率(Rate Limiting)
     */
    public static function rateLimit(string $key, int $limit, int $window): bool
    {
        $redis = new \Redis();
        $redis->connect($_ENV['REDIS_HOST'], $_ENV['REDIS_PORT']);

        $current = $redis->incr($key);
        if ($current == 1) {
            $redis->expire($key, $window);
        }

        return $current <= $limit;
    }

    /**
     * 输入验证
     */
    public static function validateEmail(string $email): bool
    {
        return filter_var($email, FILTER_VALIDATE_EMAIL) !== false;
    }

    public static function validateUrl(string $url): bool
    {
        return filter_var($url, FILTER_VALIDATE_URL) !== false;
    }

    /**
     * 防止路径遍历
     */
    public static function sanitizePath(string $path): string
    {
        return preg_replace('/\.\./', '', $path);
    }

    /**
     * 安全Headers
     */
    public static function setSecurityHeaders(): void
    {
        // 防止XSS
        header('X-XSS-Protection: 1; mode=block');

        // 防止点击劫持
        header('X-Frame-Options: SAMEORIGIN');

        // MIME类型嗅探防护
        header('X-Content-Type-Options: nosniff');

        // 内容安全策略
        header("Content-Security-Policy: default-src 'self'");

        // 严格传输安全(HTTPS)
        if ($_SERVER['HTTPS'] ?? false) {
            header('Strict-Transport-Security: max-age=31536000; includeSubDomains');
        }

        // 引荐来源策略
        header('Referrer-Policy: strict-origin-when-cross-origin');
    }
}

第八部分:性能优化与缓存

8.1 缓存服务

// app/Services/CacheService.php
<?php
namespace App\Services;

use Redis;

class CacheService
{
    private Redis $redis;
    private string $prefix;
    private int $defaultTtl;

    public function __construct(string $prefix = 'app:', int $defaultTtl = 3600)
    {
        $this->redis = new Redis();
        $this->redis->connect(
            $_ENV['REDIS_HOST'] ?? 'localhost',
            $_ENV['REDIS_PORT'] ?? 6379
        );

        if (!empty($_ENV['REDIS_PASSWORD'])) {
            $this->redis->auth($_ENV['REDIS_PASSWORD']);
        }

        $this->prefix = $prefix;
        $this->defaultTtl = $defaultTtl;
    }

    public function get(string $key)
    {
        $value = $this->redis->get($this->prefix . $key);
        return $value ? json_decode($value, true) : null;
    }

    public function set(string $key, $value, ?int $ttl = null): bool
    {
        $data = json_encode($value);
        $ttl = $ttl ?? $this->defaultTtl;
        return $this->redis->setex($this->prefix . $key, $ttl, $data);
    }

    public function delete(string $key): int
    {
        return $this->redis->del($this->prefix . $key);
    }

    public function exists(string $key): bool
    {
        return $this->redis->exists($this->prefix . $key) > 0;
    }

    public function remember(string $key, callable $callback, ?int $ttl = null)
    {
        if ($this->exists($key)) {
            return $this->get($key);
        }

        $value = $callback();
        $this->set($key, $value, $ttl);
        return $value;
    }

    public function flush(): bool
    {
        $keys = $this->redis->keys($this->prefix . '*');
        foreach ($keys as $key) {
            $this->redis->del($key);
        }
        return true;
    }

    public function increment(string $key, int $amount = 1): int
    {
        return $this->redis->incrBy($this->prefix . $key, $amount);
    }

    public function decrement(string $key, int $amount = 1): int
    {
        return $this->redis->decrBy($this->prefix . $key, $amount);
    }
}

8.2 数据库查询缓存

// app/Core/Database/CachedQueryBuilder.php
<?php
namespace App\Core\Database;

use App\Services\CacheService;

class CachedQueryBuilder extends QueryBuilder
{
    private CacheService $cache;
    private int $cacheTtl;
    private bool $shouldCache = true;

    public function __construct(string $modelClass, ?int $cacheTtl = 3600)
    {
        parent::__construct($modelClass);
        $this->cache = new CacheService('db_query:');
        $this->cacheTtl = $cacheTtl;
    }

    public function get(): array
    {
        if (!$this->shouldCache) {
            return parent::get();
        }

        $cacheKey = $this->generateCacheKey();

        return $this->cache->remember($cacheKey, function() {
            return parent::get();
        }, $this->cacheTtl);
    }

    public function first(): ?object
    {
        if (!$this->shouldCache) {
            return parent::first();
        }

        $cacheKey = $this->generateCacheKey() . ':first';

        return $this->cache->remember($cacheKey, function() {
            return parent::first();
        }, $this->cacheTtl);
    }

    public function count(): int
    {
        if (!$this->shouldCache) {
            return parent::count();
        }

        $cacheKey = $this->generateCacheKey() . ':count';

        return $this->cache->remember($cacheKey, function() {
            return parent::count();
        }, $this->cacheTtl);
    }

    public function disableCache(): self
    {
        $this->shouldCache = false;
        return $this;
    }

    public function enableCache(): self
    {
        $this->shouldCache = true;
        return $this;
    }

    public function ttl(int $seconds): self
    {
        $this->cacheTtl = $seconds;
        return $this;
    }

    private function generateCacheKey(): string
    {
        // 生成基于SQL和绑定的缓存键
        $sql = $this->buildSql();
        $key = md5($sql . json_encode($this->bindings));
        return $key;
    }

    private function buildSql(): string
    {
        $sql = "SELECT * FROM {$this->table}";

        if (!empty($this->wheres)) {
            $sql .= " WHERE " . $this->buildWhereClause();
        }

        if (!empty($this->orderBy)) {
            $sql .= " ORDER BY " . implode(', ', $this->orderBy);
        }

        if ($this->limit !== null) {
            $sql .= " LIMIT {$this->limit}";
        }

        if ($this->offset !== null) {
            $sql .= " OFFSET {$this->offset}";
        }

        return $sql;
    }
}

来源:
https://htnus.cn/category/hardware-review.html

相关文章
|
6天前
|
人工智能 JSON 监控
Claude Code 源码泄露:一份价值亿元的 AI 工程公开课
我以为顶级 AI 产品的护城河是模型。读完这 51.2 万行泄露的源码,我发现自己错了。
4343 17
|
17天前
|
人工智能 JSON 机器人
让龙虾成为你的“公众号分身” | 阿里云服务器玩Openclaw
本文带你零成本玩转OpenClaw:学生认证白嫖6个月阿里云服务器,手把手配置飞书机器人、接入免费/高性价比AI模型(NVIDIA/通义),并打造微信公众号“全自动分身”——实时抓热榜、AI选题拆解、一键发布草稿,5分钟完成热点→文章全流程!
15397 138
让龙虾成为你的“公众号分身” | 阿里云服务器玩Openclaw
|
5天前
|
人工智能 数据可视化 安全
王炸组合!阿里云 OpenClaw X 飞书 CLI,开启 Agent 基建狂潮!(附带免费使用6个月服务器)
本文详解如何用阿里云Lighthouse一键部署OpenClaw,结合飞书CLI等工具,让AI真正“动手”——自动群发、生成科研日报、整理知识库。核心理念:未来软件应为AI而生,CLI即AI的“手脚”,实现高效、安全、可控的智能自动化。
3550 8
王炸组合!阿里云 OpenClaw X 飞书 CLI,开启 Agent 基建狂潮!(附带免费使用6个月服务器)
|
7天前
|
人工智能 自然语言处理 数据挖掘
零基础30分钟搞定 Claude Code,这一步90%的人直接跳过了
本文直击Claude Code使用痛点,提供零基础30分钟上手指南:强调必须配置“工作上下文”(about-me.md+anti-ai-style.md)、采用Cowork/Code模式、建立标准文件结构、用提问式提示词驱动AI理解→规划→执行。附可复制模板与真实项目启动法,助你将Claude从聊天工具升级为高效执行系统。
|
6天前
|
人工智能 定位技术
Claude Code源码泄露:8大隐藏功能曝光
2026年3月,Anthropic因配置失误致Claude Code超51万行源码泄露,意外促成“被动开源”。代码中藏有8大未发布功能,揭示其向“超级智能体”演进的完整蓝图,引发AI编程领域震动。(239字)
2458 9