PHP项目接口权限如何统一校验拦截

wen PHP项目 27

本文目录导读:

PHP项目接口权限如何统一校验拦截

  1. Laravel 框架(中间件方案)
  2. ThinkPHP 框架(中间件方案)
  3. 原生 PHP 实现(全局拦截器)
  4. 权限管理核心设计
  5. 最佳实践建议
  6. 接口权限粒度设计

在 PHP 项目中统一进行接口权限校验拦截,核心思路是使用 中间件事件驱动 模式,在请求到达具体控制器方法之前完成鉴权,以下是几种主流且高效的实现方案:

Laravel 框架(中间件方案)

Laravel 提供了最完善的中间件机制。

1 创建权限中间件

php artisan make:middleware CheckPermission

2 实现校验逻辑

<?php
namespace App\Http\Middleware;
use Closure;
use Illuminate\Http\Request;
use App\Models\User;
use Illuminate\Support\Facades\Route;
class CheckPermission
{
    public function handle(Request $request, Closure $next)
    {
        // 获取当前用户(假设通过 JWT/Session 已认证)
        $user = auth()->user();
        if (!$user) {
            return response()->json(['message' => '未认证'], 401);
        }
        // 获取当前路由名称
        $routeName = Route::currentRouteName();
        // 或者使用:$routeName = $request->route()->getName();
        // 定义不需要权限检查的路由(白名单)
        $whitelist = ['login', 'register', 'forgot-password'];
        if (in_array($routeName, $whitelist)) {
            return $next($request);
        }
        // 检查用户权限(可根据业务定制)
        if (!$user->hasPermission($routeName)) {
            return response()->json([
                'message' => '权限不足',
                'required_permission' => $routeName
            ], 403);
        }
        return $next($request);
    }
}

3 注册中间件

app/Http/Kernel.php 中注册:

protected $routeMiddleware = [
    // ...
    'permission' => \App\Http\Middleware\CheckPermission::class,
];

4 应用到路由组

Route::middleware(['auth:api', 'permission'])->group(function () {
    Route::get('/users', [UserController::class, 'index'])->name('users.list');
    Route::post('/users', [UserController::class, 'store'])->name('users.create');
    Route::put('/users/{id}', [UserController::class, 'update'])->name('users.update');
});

ThinkPHP 框架(中间件方案)

1 定义中间件

<?php
namespace app\middleware;
use Closure;
use think\Request;
use think\Response;
class CheckPermission
{
    public function handle($request, Closure $next)
    {
        // 获取当前用户(假设已认证)
        $user = $request->user;
        if (!$user) {
            return Response::create(['message' => '未认证'], 401);
        }
        // 获取当前控制器和方法
        $controller = $request->controller();
        $action = $request->action();
        $permissionKey = "{$controller}@{$action}";
        // 定义白名单
        $whitelist = ['Index@login', 'Index@register'];
        if (in_array($permissionKey, $whitelist)) {
            return $next($request);
        }
        // 权限检查
        if (!$user->can($permissionKey)) {
            return Response::create(['message' => '权限不足'], 403);
        }
        return $next($request);
    }
}

2 注册中间件

config/middleware.php 中:

return [
    'CheckPermission' => app\middleware\CheckPermission::class,
];

3 应用到路由

Route::group(['middleware' => ['auth', 'CheckPermission']], function () {
    Route::get('users', 'User/index');
    Route::post('users', 'User/create');
});

原生 PHP 实现(全局拦截器)

如果不使用框架,可以创建一个统一的入口文件:

<?php
// index.php - 统一入口
require_once 'config.php';
require_once 'auth.php';
class Router {
    public static function handle() {
        $uri = $_SERVER['REQUEST_URI'];
        $method = $_SERVER['REQUEST_METHOD'];
        // 路由解析
        $route = self::parseRoute($uri, $method);
        // 权限校验
        if (!self::checkPermission($route)) {
            http_response_code(403);
            echo json_encode(['message' => '权限不足']);
            exit;
        }
        // 执行控制器
        $controller = new $route['controller']();
        $action = $route['action'];
        echo $controller->$action();
    }
    private static function checkPermission($route) {
        // 白名单
        $whitelist = [
            ['controller' => 'AuthController', 'action' => 'login'],
            ['controller' => 'AuthController', 'action' => 'register'],
        ];
        foreach ($whitelist as $item) {
            if ($item['controller'] == $route['controller'] && 
                $item['action'] == $route['action']) {
                return true;
            }
        }
        // JWT 验证用户
        $token = $_SERVER['HTTP_AUTHORIZATION'] ?? '';
        $user = validateJWT($token);
        if (!$user) {
            return false;
        }
        // 检查权限
        return $user->hasPermission($route['controller'], $route['action']);
    }
}
Router::handle();

权限管理核心设计

1 权限存储结构

-- 用户-角色-权限 多对多关系
CREATE TABLE permissions (
    id INT PRIMARY KEY,
    name VARCHAR(100) UNIQUE,  -- 'users.list', 'users.create'
    display_name VARCHAR(200),
    description TEXT
);
CREATE TABLE roles (
    id INT PRIMARY KEY,
    name VARCHAR(100) UNIQUE,
    display_name VARCHAR(200)
);
CREATE TABLE role_permission (
    role_id INT,
    permission_id INT,
    PRIMARY KEY (role_id, permission_id)
);
CREATE TABLE user_role (
    user_id INT,
    role_id INT,
    PRIMARY KEY (user_id, role_id)
);

2 权限检查逻辑示例

class User {
    public function hasPermission($permissionName) {
        // 超级管理员拥有所有权限
        if ($this->is_super_admin) {
            return true;
        }
        $roles = $this->roles()->with('permissions')->get();
        foreach ($roles as $role) {
            foreach ($role->permissions as $permission) {
                if ($permission->name === $permissionName) {
                    return true;
                }
            }
        }
        return false;
    }
}

最佳实践建议

1 注解方式(适用于大型项目)

// Laravel 扩展
#[Permission('users.create')]
public function store(Request $request) {
    // ...
}

2 缓存优化

// 使用 Redis 缓存用户权限
class UserPermissionCache {
    public function hasPermission($userId, $permissionName) {
        $key = "user_permissions:{$userId}";
        // 检查缓存
        if (Cache::has($key)) {
            $permissions = Cache::get($key);
            return in_array($permissionName, $permissions);
        }
        // 从数据库加载并缓存(缓存1小时)
        $user = User::find($userId);
        $permissions = $user->getAllPermissions()->pluck('name')->toArray();
        Cache::put($key, $permissions, 3600);
        return in_array($permissionName, $permissions);
    }
}

3 日志记录

// 在中间件中记录权限检查日志
Log::channel('permission')->info('权限检查', [
    'user_id' => $user->id,
    'route' => $routeName,
    'result' => $hasPermission ? '通过' : '拒绝',
    'ip' => $request->ip(),
    'time' => now()
]);

接口权限粒度设计

建议采用三级管控:

  1. 路由级别:控制能否访问某个接口
  2. 数据级别:控制能看到哪些数据(自己的/部门的/全部的)
  3. 字段级别:控制能查看/修改哪些字段

示例:

// 数据权限中间件
class DataPermissionMiddleware {
    public function handle($request, $next) {
        // 获取用户
        $user = auth()->user();
        // 根据角色决定数据范围
        switch ($user->data_scope) {
            case 'self':
                // 只返回自己的数据
                $request->merge(['user_filter' => $user->id]);
                break;
            case 'department':
                // 返回部门数据
                $request->merge(['department_filter' => $user->department_id]);
                break;
            case 'all':
                // 返回所有数据
                break;
        }
        return $next($request);
    }
}

选择方案时需要考虑:

  • 小项目:使用原生 PHP 的全局拦截器
  • 中型项目:ThinkPHP/Laravel 的中间件
  • 大型分布式:API 网关(如 Kong)+ 微服务中间件
  • 性能敏感:配合缓存(Redis)+ 预编译权限位运算

无论哪种方案,核心思想都是:在请求进入业务逻辑之前,通过统一的拦截点完成身份验证和权限校验

抱歉,评论功能暂时关闭!