
本文介绍如何在 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 App\Http\Middleware;
use Closure;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Session;
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', [Account\SendPackageController::class, 'index'])
->name('cms-history-send-packages')
->middleware(['company', '2fa']); // ← 新增 '2fa' 别名
Route::get('/cms-przesyleka-nadana/{id}', [Account\SendPackageController::class, 'show'])
->name('cms-view-send-package')
->middleware(['company', '2fa']);
// ... 其他敏感路由同理,均追加 '2fa'
// 2FA 设置页本身不参与验证,保持开放
Route::get('/cms-dwu-stopniowa-weryfikacja', [Account\TwoStepVerificationController::class, 'index'])
->name('cms-two-step-verification');
});同时,在 app/Http/Kernel.php 中注册中间件别名:
protected $routeMiddleware = [
// ...
'2fa' => \App\Http\Middleware\Check2FA::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 权限与认证体系进阶落地的典型范式。










