【问题标题】:Use Multiple Middleware for Combined Routes in Laravel 8在 Laravel 8 中使用多个中间件进行组合路由
【发布时间】:2022-02-24 22:36:09
【问题描述】:

我将在我的应用程序中将所有路由分配给管理员角色,将一些路由分配给操作角色,并将一些路由分配给其他角色。我尝试在 Laravel 8 中使用组中间件。

仅管理员角色的代码就可以正常工作。但是,当我将中间件添加到路由组中的其他角色时,它的功能并没有达到我的预期。

我的代码:

Web.php:

    Route::middleware(['role:Admin'])->group(function () {
        Route::get('/', function () {
            return redirect('/home');
        });
     
        Route::get('/home', [App\Http\Controllers\HomeController::class, 'index'])->name('home');
        
        Route::get('/employee_register', [App\Http\Controllers\EmployeeRegisterController::class, 'index'])->name('employee_register');
        
        Route::post('/employee_register', [App\Http\Controllers\EmployeeRegisterController::class, 'save'])->name('employee_save');
        
        Route::post('/DoAsync', [App\Http\Controllers\AjaxController::class,'ajaxTask'])->middleware('only.ajax');
        
        Route::get('/job_booking', [App\Http\Controllers\JobBookingController::class, 'index'])->name('job_booking');
        
        Route::post('/DoAsync_jb', [App\Http\Controllers\JobBookingAjaxController::class,'ajaxTask'])->middleware('only.ajax');
        
        Route::post('/DoAsync_ai', [App\Http\Controllers\AssignInchargeAjaxController::class,'ajaxTask'])->middleware('only.ajax');
        
    });

    
Route::middleware(['role:operation'])->group(function () {
        
        Route::get('/', function () {
        
            return redirect('/job_booking');
        
        });
     
        
        Route::get('/home', function(){
        
            return redirect('/job_booking');
    
        })->name('home');
        
        
        Route::get('/job_booking', [App\Http\Controllers\JobBookingController::class, 'index'])->name('job_booking');
        
        Route::post('/DoAsync_jb', [App\Http\Controllers\JobBookingAjaxController::class,'ajaxTask'])->middleware('only.ajax');
        
        Route::post('/DoAsync_ai', [App\Http\Controllers\AssignInchargeAjaxController::class,'ajaxTask'])->middleware('only.ajax');
        
    });

中间件 (EnsureUserHasRole):

class EnsureUserHasRole
    {
        
        public function handle(Request $request, Closure $next, string $role)
        {
            
            //I received Call to a member function roles() on null error when accessing login and logout. 
            // So, I used this to avoid role check on login & logout routes.
            
            if ( $request->route()->named('login') || $request->route()->named('logout') ) {
                
                return $next($request);
    
            }
            
             
            elseif ($request->user()->roles()->where('role', '=', $role)->exists()) {
    
                return $next($request);
    
            }
                    
            abort(403);
    
        }
    
    }

型号:

用户:

class User extends Authenticatable
{
    use HasApiTokens, HasFactory, Notifiable;

    
    protected $fillable = [
        'employee_id',
        'name',
        'email',
        'password',
    ];

    
    protected $hidden = [
        'password',
        'remember_token',
    ];

    
    protected $casts = [
        'email_verified_at' => 'datetime',
    ];


    public function roles()
    {
        return $this->belongsToMany(Role::class, 'role_user');
    }
    
}

角色:

class Role extends Model
{
    use HasFactory;

    public function users()
    {
        return $this->belongsToMany(User::class, 'role_user');
    }
    
}

如果没有第二个中间件 (middleware(['role:operation'])),所有路由都将被访问。但是,然后添加它,EnsureUserHasRole 中间件中的if 条件执行abort(403)

我应该在web.php的中间件中使用任何if吗?

注意:middleware('only.ajax') 已用于确保仅在 Ajax 调用时访问控制器

【问题讨论】:

    标签: php laravel routes laravel-8 laravel-middleware


    【解决方案1】:

    您正在复制路线。如果您运行php artisan route:list,您会发现一半的路线丢失了。

    我们以'/'为例,你所做的与此类似:

    Route::get('/', function () {
        return redirect('/home');
    })->middleware(['role:Admin']);
    
    Route::get('/', function () {
        return redirect('/job_booking');
    })->middleware(['role:operation']);
    

    如您所见,路线重复。

    为避免这种情况,您需要为您的路线添加前缀,例如:

    Route::get('/admin', function () {
        return redirect('/home');
    })->middleware(['role:Admin']);
    
    Route::get('/operation', function () {
        return redirect('/job_booking');
    })->middleware(['role:operation']);
    

    查看Laravel Routing了解更多信息。

    【讨论】:

    • 为了进一步解释,路由和它们调用的控制器函数之间存在直接的 1:1 关系。中间件不用作条件,因为用户可能同时是操作和管理员角色,而 Laravel 不知道将它们发送到哪里。需要更多的逻辑来按角色进行路由。
    猜你喜欢
    • 2021-12-29
    • 2017-04-14
    • 2019-03-26
    • 1970-01-01
    • 2019-04-30
    • 2016-12-09
    • 2020-01-11
    • 2020-01-20
    • 2021-05-12
    相关资源
    最近更新 更多