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月前
|
人工智能 API 开发工具
AskTable:可嵌入任何系统的 AI 数据智能体引擎
AskTable 是一款以 Table 为核心的数据 AI 基础设施。它通过标准化 API、SDK、iFrame 与智能体协议(MCP),让 AI 能直接理解、查询和分析表格数据,轻松嵌入企业现有系统。 AskTable 提供从数据接入、语义分析到可视化生成的完整能力,可无缝集成至网页、移动端、钉钉、企业微信或 Dify/HiAgent 等智能体平台。
776 157
|
22天前
|
人工智能 运维 监控
OpenClaw 10大自动化场景实战|阿里云轻量服务器部署+零基础避坑指南
2026年,OpenClaw已成为普通人拥有“AI员工”的最低门槛工具——无需编程基础,通过简单配置即可落地10大自动化场景,让效率提升3倍以上。本文完整覆盖**新手零基础阿里云轻量服务器部署OpenClaw(Clawdbot)简单步骤及避坑指南**,从部署、配置到场景落地,全程提供可直接复制的代码与指引,确保用户快速上手。
247 8
|
5天前
|
资源调度 数据可视化 前端开发
前端组件库——DataV知识点大全(一)
教程来源 https://www.wkmsa.cn DataV是专注大屏可视化的开源Vue组件库,提供丰富SVG边框、装饰与图表组件,助力快速构建震撼数据看板。基于Vue3+TS重构,支持主题定制与按需引入;3.0版将集成WebGPU,性能提升47%。开箱即用,大幅降低开发门槛。
|
6天前
|
移动开发 JavaScript 前端开发
前端组件库——Wot Design Uni知识点大全(一)
教程来源 https://zlpow.cn Wot Design Uni 是基于 Vue3 + TypeScript 的开源 uni-app UI 组件库,提供 70+ 高质量移动端组件,支持微信/支付宝小程序、H5、App 等多端兼容,内置暗黑模式、国际化(15+语言)与 CSS 变量主题定制,大幅提升跨平台开发效率。
|
9天前
|
人工智能 前端开发 JavaScript
前端组件库——shadcn/ui知识点大全(三)
教程来源 http://lemci.cn/ shadcn/ui通过Tree Shaking、动态导入、Tailwind JIT等实现极致性能优化,Bundle仅增20–50KB;组件即代码,完全可控、可定制、易维护,契合Next.js+Tailwind现代栈与AI协作开发。
|
9天前
|
前端开发 JavaScript 数据可视化
前端组件库——Radix UI知识点大全(一)
教程来源 https://bncne.cn/ Radix UI是React生态中革命性的无样式组件原语库,专注提供高可访问性、键盘导航完备、ARIA合规的底层交互逻辑,将样式完全交由开发者掌控,完美平衡定制自由与无障碍标准,已成为shadcn/ui等主流工具的底层基石。
|
14天前
|
JavaScript 前端开发 安全
前端组件库——Naive UI知识点大全(一)
教程来源 https://hllft.cn/category/artificial-intelligence.html Naive UI是Vue 3 + TypeScript现代化UI库,由图森未来开源。主打轻量、高性能、零CSS导入、全组件Tree Shaking及类型安全主题系统,已获GitHub 1.5w+ Star,适合追求开发体验与性能的中后台项目。
|
11天前
|
资源调度 前端开发 JavaScript
前端组件库——Tailwind CSS知识点大全(一)
教程来源 https://xcfsr.cn/category/software-dev.html Tailwind CSS是2017年开源的工具优先(utility-first)CSS框架,提供数百个细粒度工具类,让开发者直接在HTML中组合样式,无需写自定义CSS。v4.0引入Oxide引擎与CSS优先配置,性能与体验全面升级,现为全球最流行的CSS框架。
|
14天前
|
JavaScript 前端开发 API
前端组件库——Element Plus知识点大全(一)
教程来源 https://tmywi.cn/category/lvxing.html Element Plus是饿了么团队打造的Vue 3官方UI库,深度集成TypeScript与Composition API,提供70+企业级组件、完善设计规范及主题定制能力。GitHub星标超2.5万,国内Vue 3中后台开发首选方案。