
本文介绍如何在 Laravel 中基于已登录用户的 role 字段,动态生成路由前缀(如 /superadmin/ 或 /admindesa/),并通过中间件自动注入角色值,实现角色感知的路由分组与控制器参数传递。
本文介绍如何在 laravel 中基于已登录用户的 `role` 字段,动态生成路由前缀(如 `/superadmin/` 或 `/admindesa/`),并通过中间件自动注入角色值,实现角色感知的路由分组与控制器参数传递。
在 Laravel 中,若希望路由前缀(prefix)能根据当前认证用户的权限角色动态变化(例如:/superadmin/dashboard 和 /admindesa/penduduk),不能直接在 Route::group() 中写死 {User Role} 占位符——Laravel 路由定义阶段无法访问运行时用户上下文。正确做法是:将前缀设为通配符 {role},再通过中间件校验并显式注入角色值到请求对象中,从而实现“路由即角色”的语义化设计。
✅ 正确实现步骤
1. 定义动态角色前缀路由
在 routes/web.php 中,使用 {role} 作为路由前缀占位符,并搭配角色校验中间件:
// 动态角色前缀路由组(匹配 /{role}/...)
Route::group(['prefix' => '{role}', 'middleware' => 'authuser:superadmin,admindesa'], function () {
Route::get('/', [DashboardC::class, 'index']);
Route::get('/penduduk', [PendudukC::class, 'index']);
Route::get('/penduduk/{id}/detail', [PendudukC::class, 'detail']);
});
// 独立角色专用路由组(无通配符,用于严格限定)
Route::group(['prefix' => 'superadmin', 'middleware' => 'authuser:superadmin'], function () {
Route::get('/pengguna', [PenggunaC::class, 'index']);
Route::get('/pengguna/{id}/edit', [PenggunaC::class, 'edit']);
Route::post('/pengguna/{id}/prosesedit', [PenggunaC::class, 'prosesEdit']);
Route::get('/pengguna/{id}/hapus', [PenggunaC::class, 'hapus']);
Route::post('/ajax/pengguna', [AjaxC::class, 'pengguna']);
});
⚠️ 注意:
{role}是路由参数,不是字符串插值;它会捕获 URL 第一段路径(如https://app.com/admindesa/penduduk中的admindesa),但不自动校验是否匹配用户真实角色——这需由中间件完成。
2. 增强中间件:校验角色 + 注入请求属性
修改自定义中间件 AuthUser(建议重命名为 RolePrefixAuth 并注册为 authuser 别名),关键点在于:校验通过后,将 $auth->role 显式赋值给 $request->role,使后续控制器可安全使用:
Laravel Cloud(cloud.laravel.com)。此技能用于处理所有 Laravel Cloud 请求,包括搜索和读取数据。只要任务涉及 Laravel Cloud,即使用此技能。
// app/Http/Middleware/AuthUser.php
<?php namespace App\Http\Middleware;
use Closure;
use Illuminate\Http\Request;
class AuthUser
{
public function handle(Request $request, Closure $next, ...$allowedRoles)
{
$auth = auth('web')->user();
if (!$auth || !in_array($auth->role, $allowedRoles)) {
return redirect()->route('login')
->with('gagal', 'Silahkan login untuk melanjutkan');
}
// ✅ 核心:将用户角色注入请求对象,供控制器读取
$request->role = $auth->role;
return $next($request);
}
}
✅ 优势:
$request->role可在任意控制器方法中直接访问,无需重复查询用户模型,且与路由参数{role}解耦(避免因 URL 伪造导致逻辑错误)。
3. 控制器中接收并使用角色参数
当路由含 {role} 占位符时,Laravel 会自动将该段路径值作为第一个参数注入控制器方法。必须按顺序声明 $role 参数(位于 $id 等其他参数之前):
// app/Http/Controllers/PendudukC.php
public function detail(Request $request, string $role, int $id)
{
// $role 来自 URL 路径(如 /admindesa/penduduk/123/detail)
// $request->role 来自中间件注入(确保与当前登录用户一致)
// 可选:双重校验(增强安全性)
if ($role !== $request->role) {
abort(403, 'Role mismatch');
}
$penduduk = Penduduk::with([
'kabupaten', 'kecamatan', 'kelurahan', 'dusun', 'pendudukjb'
])->find($id);
$bantuan = array_column(
json_decode($penduduk->pendudukjb, true),
'id_master_jenis_bantuan'
);
$view = $request->modal ? 'penduduk/_detail' : 'penduduk/detail';
return view($view, compact('penduduk', 'bantuan'));
}
? 补充说明与最佳实践
-
路由参数 vs 请求属性:
{role}是 URL 路径参数(易被篡改),而$request->role是中间件注入的可信值。推荐以$request->role为准,必要时做一致性校验。 -
中间件注册:确保在
app/Http/Kernel.php的$routeMiddleware中注册:'authuser' => \App\Http\Middleware\AuthUser::class,
-
避免冲突:动态
{role}路由应放在静态前缀路由(如superadmin)之后,防止路由匹配优先级问题。 - SEO 与体验:动态前缀对 SEO 无实质影响,但需确保所有角色专属页面均通过合法登录进入,避免未授权访问。
通过以上方式,你既能实现语义清晰的 /{role}/ 路由结构,又能保障权限逻辑的健壮性与可维护性。










