Laravel 5.5 利用中间件基于角色权限实现路由保护
嘿,我来帮你搞定这个Laravel 5.5的路由权限保护问题~你之前用if语句的思路虽然能跑,但确实不够优雅也不好维护,Laravel本身提供了更标准的解决方案——中间件,这也是处理路由权限的最佳实践,我给你详细拆解几个可行的方案:
方案一:针对管理员的专属中间件(最简单直接)
如果只是需要保护管理员(role_id=2)的路由,专门写一个管理员验证中间件就够了:
1. 创建中间件
在终端执行命令生成中间件文件:
php artisan make:middleware CheckAdmin
打开生成的 app/Http/Middleware/CheckAdmin.php,写入权限验证逻辑:
<?php namespace App\Http\Middleware; use Closure; use Illuminate\Support\Facades\Auth; class CheckAdmin { public function handle($request, Closure $next) { // 先判断用户是否已登录 if (!Auth::check()) { return redirect('/login'); // 未登录直接跳转到登录页 } $currentUser = Auth::user(); // 验证用户是否是管理员(role_id=2) if ($currentUser->role_id !== 2) { // 非管理员跳回首页,还可以加个错误提示 return redirect()->route('home')->with('error', '抱歉,你没有访问该页面的权限'); } // 验证通过,继续请求 return $next($request); } }
2. 注册中间件
打开 app/Http/Kernel.php,在 $routeMiddleware 数组里添加这个中间件的别名:
protected $routeMiddleware = [ // 保留原来的其他中间件... 'admin' => \App\Http\Middleware\CheckAdmin::class, ];
3. 给路由添加保护
现在你可以在 web.php 里给管理员路由分组,直接用这个中间件:
// 所有管理员专属路由都放在这个组里 Route::middleware('admin')->group(function () { Route::get('/admin','AdminController@index')->name('admin'); // 后续新增的管理员路由都可以加在这里,不用重复写判断 });
方案二:通用角色验证中间件(支持多角色)
如果需要给不同角色(比如所有者1、版主3)都做路由保护,写一个通用的中间件更灵活:
1. 创建通用角色中间件
执行命令生成中间件:
php artisan make:middleware CheckRole
编辑 app/Http/Middleware/CheckRole.php,实现支持多角色参数的逻辑:
<?php namespace App\Http\Middleware; use Closure; use Illuminate\Support\Facades\Auth; class CheckRole { public function handle($request, Closure $next, ...$allowedRoles) { if (!Auth::check()) { return redirect('/login'); } $userRole = Auth::user()->role_id; // 检查用户角色是否在允许的列表里 if (!in_array($userRole, $allowedRoles)) { return redirect()->route('home')->with('error', '权限不足,无法访问'); } return $next($request); } }
2. 注册中间件
同样在 Kernel.php 的 $routeMiddleware 里添加:
protected $routeMiddleware = [ // ...其他中间件 'role' => \App\Http\Middleware\CheckRole::class, ];
3. 灵活使用路由保护
现在你可以给不同路由指定允许的角色:
// 所有者(1)和管理员(2)都能访问的路由组 Route::middleware('role:1,2')->group(function () { Route::get('/admin','AdminController@index')->name('admin'); Route::get('/owner-dashboard','OwnerController@index')->name('owner.dashboard'); }); // 只有版主(3)能访问的路由 Route::get('/mod-panel','ModController@index')->name('mod.panel')->middleware('role:3');
额外处理:封禁用户(role_id=4)的拦截
针对封禁用户,最好做一个全局中间件,确保他们无法访问任何内容:
1. 创建封禁检查中间件
php artisan make:middleware CheckBanned
编辑 app/Http/Middleware/CheckBanned.php:
<?php namespace App\Http\Middleware; use Closure; use Illuminate\Support\Facades\Auth; class CheckBanned { public function handle($request, Closure $next) { if (Auth::check() && Auth::user()->role_id === 4) { Auth::logout(); // 强制退出封禁用户 return redirect('/login')->with('error', '你的账号已被封禁,无法登录'); } return $next($request); } }
2. 注册为全局中间件
打开 Kernel.php,把这个中间件加到 $middleware 数组里(全局中间件会拦截所有请求):
protected $middleware = [ // ...原来的全局中间件 \App\Http\Middleware\CheckBanned::class, ];
为什么不推荐你原来的if写法?
直接在路由文件里写if判断虽然能临时解决问题,但当路由越来越多的时候,代码会变得杂乱不堪,而且权限逻辑分散在路由文件里,后续修改或扩展会非常麻烦。用中间件的话,权限逻辑集中在一个地方,维护和扩展都更方便,也符合Laravel的设计规范。
如果后续需要更细粒度的权限控制(比如某个控制器方法的权限),还可以结合Laravel的Gate和Policy来实现,但路由级别的保护用中间件就足够简单高效了。
内容的提问来源于stack exchange,提问作者daugaard47

