如何实现ThinkPHP路由中间件自定义与权限控制?
- 内容介绍
- 文章标签
- 相关推荐
本文共计994个文字,预计阅读时间需要4分钟。
ThinkPHP 是一款流行的 PHP 开源框架,广泛应用于企业级网站和应用程序的开发。它以其简洁易用、功能强大而受到开发者的青睐。以下是其核心特点:
如何给单个路由绑定中间件
最直接的方式是在 route/app.php 中定义路由时用 middleware 方法链式调用:
// route/app.php use think\facade\Route; Route::get('admin/user/list', 'admin.UserController@list') ->middleware('check_auth'); // 绑定中间件名(字符串)
注意:check_auth 是你在 app/middleware.php 或中间件类中注册的别名,不是类全名;如果没注册别名,得写完整类名:\app\middleware\CheckAuth::class。
常见错误:把中间件名写成未注册的字符串,运行时报 Middleware not found: xxx;或者误用 ->middleware(['check_auth']) 传数组却只绑一个,虽不报错但冗余。
立即学习“PHP免费学习笔记(深入)”;
如何给路由分组统一绑定权限中间件
后台模块、API 版本前缀这类场景,用 group + middleware 最省事:
Route::group('admin', function () { Route::get('user/list', 'admin.UserController@list'); Route::post('user/add', 'admin.UserController@add'); })->middleware('check_auth');
这样比每个路由单独写更安全,也避免遗漏。但要注意:group 的中间件是“前置执行”,不会因为子路由用了 allowCrossDomain 等其他中间件就跳过权限检查。
关键点:
- group 的中间件对所有子路由生效,包括闭包路由和资源路由
- 如果子路由又单独调用了
->middleware(),会叠加执行(不是覆盖),顺序按绑定先后 - 资源路由(
Route::resource())必须在 group 内定义,否则 group 中间件不生效
为什么不能在中间件里靠 $request->url() 做路由级判断
有人试图在中间件里解析当前 URL 字符串,再查配置表做权限控制,这会导致三个问题:
第一,URL 可能带参数(如 /user/edit/123),硬匹配会失败;第二,ThinkPHP 路由支持变量规则([:id])、正则约束,字符串比对无法还原原始路由定义;第三,闭包路由和动态注册路由根本没“名称”,无法反查。
正确做法是:在路由定义阶段就打上权限标识,比如用 option 注入权限码:
Route::get('admin/log', 'admin.LogController@index') ->option(['auth_rule' => 'log:read']);
然后在中间件里用 $request->rule()->getOption('auth_rule') 拿到它——这才是 ThinkPHP 原生支持的、可靠的路由元数据获取方式。
中间件中如何获取当前路由的真实操作方法
权限系统常需知道“用户是否拥有访问 admin.UserController@delete 的权限”,但 $request->action() 返回的是方法名(如 delete),不带控制器。可靠方式是组合使用:
$controller = $request->controller(); // 返回 'User' $action = $request->action(); // 返回 'delete' $module = $request->module(); // 返回 'admin' $fullAction = $module . '.' . $controller . '@' . $action; // 'admin.User@delete'
注意:$request->controller() 返回值默认首字母大写,但实际类名可能驼峰(UserList),所以更稳妥的是从路由规则里取原始调度信息:$request->rule()->getAction()(返回完整类方法字符串,如 app\controller\admin\UserController@list)。
这个细节在 RBAC 权限校验时特别关键——控制器名大小写、命名空间层级稍有偏差,权限就判错。
本文共计994个文字,预计阅读时间需要4分钟。
ThinkPHP 是一款流行的 PHP 开源框架,广泛应用于企业级网站和应用程序的开发。它以其简洁易用、功能强大而受到开发者的青睐。以下是其核心特点:
如何给单个路由绑定中间件
最直接的方式是在 route/app.php 中定义路由时用 middleware 方法链式调用:
// route/app.php use think\facade\Route; Route::get('admin/user/list', 'admin.UserController@list') ->middleware('check_auth'); // 绑定中间件名(字符串)
注意:check_auth 是你在 app/middleware.php 或中间件类中注册的别名,不是类全名;如果没注册别名,得写完整类名:\app\middleware\CheckAuth::class。
常见错误:把中间件名写成未注册的字符串,运行时报 Middleware not found: xxx;或者误用 ->middleware(['check_auth']) 传数组却只绑一个,虽不报错但冗余。
立即学习“PHP免费学习笔记(深入)”;
如何给路由分组统一绑定权限中间件
后台模块、API 版本前缀这类场景,用 group + middleware 最省事:
Route::group('admin', function () { Route::get('user/list', 'admin.UserController@list'); Route::post('user/add', 'admin.UserController@add'); })->middleware('check_auth');
这样比每个路由单独写更安全,也避免遗漏。但要注意:group 的中间件是“前置执行”,不会因为子路由用了 allowCrossDomain 等其他中间件就跳过权限检查。
关键点:
- group 的中间件对所有子路由生效,包括闭包路由和资源路由
- 如果子路由又单独调用了
->middleware(),会叠加执行(不是覆盖),顺序按绑定先后 - 资源路由(
Route::resource())必须在 group 内定义,否则 group 中间件不生效
为什么不能在中间件里靠 $request->url() 做路由级判断
有人试图在中间件里解析当前 URL 字符串,再查配置表做权限控制,这会导致三个问题:
第一,URL 可能带参数(如 /user/edit/123),硬匹配会失败;第二,ThinkPHP 路由支持变量规则([:id])、正则约束,字符串比对无法还原原始路由定义;第三,闭包路由和动态注册路由根本没“名称”,无法反查。
正确做法是:在路由定义阶段就打上权限标识,比如用 option 注入权限码:
Route::get('admin/log', 'admin.LogController@index') ->option(['auth_rule' => 'log:read']);
然后在中间件里用 $request->rule()->getOption('auth_rule') 拿到它——这才是 ThinkPHP 原生支持的、可靠的路由元数据获取方式。
中间件中如何获取当前路由的真实操作方法
权限系统常需知道“用户是否拥有访问 admin.UserController@delete 的权限”,但 $request->action() 返回的是方法名(如 delete),不带控制器。可靠方式是组合使用:
$controller = $request->controller(); // 返回 'User' $action = $request->action(); // 返回 'delete' $module = $request->module(); // 返回 'admin' $fullAction = $module . '.' . $controller . '@' . $action; // 'admin.User@delete'
注意:$request->controller() 返回值默认首字母大写,但实际类名可能驼峰(UserList),所以更稳妥的是从路由规则里取原始调度信息:$request->rule()->getAction()(返回完整类方法字符串,如 app\controller\admin\UserController@list)。
这个细节在 RBAC 权限校验时特别关键——控制器名大小写、命名空间层级稍有偏差,权限就判错。

