
本文介绍如何在 laravel 8 中结合 spatie/laravel-permission,为特定路由动态启用双因素认证(2FA),仅当当前登录用户 is_two_step_authorization = 1 且未完成验证时才触发跳转,实现细粒度、按需生效的安全控制。
本文介绍如何在 laravel 8 中结合 spatie/laravel-permission,为特定路由动态启用双因素认证(2fa),仅当当前登录用户 `is_two_step_authorization = 1` 且未完成验证时才触发跳转,实现细粒度、按需生效的安全控制。
在构建多角色企业级应用(如个体用户与公司用户共存)时,安全策略不应“一刀切”。例如,您可能希望仅对启用了双因素认证(2FA)的公司用户,在访问敏感操作(如查看寄出/接收包裹历史、下载 PDF 凭证等)时强制执行二次验证;而对未开启该功能的用户则完全绕过,保持体验流畅。这要求中间件具备运行时用户上下文感知能力,而非静态绑定到路由。
✅ 正确做法:创建动态感知型中间件
首先,生成自定义中间件:
php artisan make:middleware Check2FA
然后编辑 app/http/Middleware/Check2FA.php,关键逻辑在于:仅当当前用户已启用 2FA 且尚未通过验证时才拦截请求:
<?php namespace AppHttpMiddleware; use Closure; use IlluminateHttpRequest; use IlluminateSupportFacadessession; class Check2FA { public function handle(Request $request, Closure $next) { // 确保用户已登录(避免未登录时调用 $request->user() 报错) $user = $request->user(); if (!$user) { return $next($request); } // 核心判断:仅当用户启用双因素认证,且 session 中无有效 2FA 标识时重定向 if ($user->is_two_step_authorization && !Session::has('user_2fa')) { return redirect()->route('2fa.index'); // 假设您的 2FA 首页路由名为 '2fa.index' } return $next($request); } }
⚠️ 注意事项:
- 必须前置身份验证中间件:确保 Check2FA 在 auth 或 auth:sanctum 之后执行(在 app/Http/Kernel.php 的 $middlewareGroups[‘web’] 中,将其置于 auth 后);
- Session 有效性保障:Session::has(‘user_2fa’) 应在用户成功完成 2FA 后由您的验证控制器(如 TwoStepVerificationController@verify)手动设置,例如:Session::put(‘user_2fa’, true);
- 避免无限重定向:确保 2fa.index 路由本身不应用 Check2FA 中间件,否则将导致循环跳转。
? 集成到现有路由组
修改您原有的路由定义,将 Check2FA 中间件添加至需要受控的子路由(而非整个外层 group),以精准作用于敏感操作:
Route::group(['prefix' => '', 'middleware' => ['role:individual|company']], function () { // 所有 company 权限路由均需先过角色检查,再按用户配置决定是否触发 2FA Route::get('/cms-historia-przesylek-nadanych', [AccountSendPackageController::class, 'index']) ->name('cms-history-send-packages') ->middleware(['company', '2fa']); // ← 新增 '2fa' 别名 Route::get('/cms-przesyleka-nadana/{id}', [AccountSendPackageController::class, 'show']) ->name('cms-view-send-package') ->middleware(['company', '2fa']); // ... 其他敏感路由同理,均追加 '2fa' // 2FA 设置页本身不参与验证,保持开放 Route::get('/cms-dwu-stopniowa-weryfikacja', [AccountTwoStepVerificationController::class, 'index']) ->name('cms-two-step-verification'); });
同时,在 app/Http/Kernel.php 中注册中间件别名:
protected $routeMiddleware = [ // ... '2fa' => AppHttpMiddlewareCheck2FA::class, ];
? 补充建议与最佳实践
- 数据库字段确认:确保 users.is_two_step_authorization 字段已正确迁移并设为 tinyInteger(1)->default(0),并在模型中添加访问器提升可读性:
// 在 User.php 中添加 public function getIsTwoStepAuthorizationAttribute($value) { return (bool) $value; } - 退出时清理 Session:用户登出时应清除 2FA 状态,防止会话残留:
// 在登出逻辑中(如 LoginController@logout) Session::forget('user_2fa'); - 用户体验优化:可在 2FA 页面显示提示:“您已启用双因素认证,访问敏感功能前需验证身份”,增强透明度。
通过以上实现,您不再依赖全局或静态中间件,而是让安全策略真正“因人而异”——既满足合规性要求,又兼顾不同用户的实际安全偏好,是 Laravel 权限与认证体系进阶落地的典型范式。