无法基于角色 Laravel 8 保护路由
Posted
技术标签:
【中文标题】无法基于角色 Laravel 8 保护路由【英文标题】:Can't protect Routes based on role Laravel 8 【发布时间】:2021-11-12 11:34:05 【问题描述】:我正在尝试使用中间件来保护基于角色的路由。
我正在测试这条路线,只允许角色administrador
能够进入它。
Route::get('/gestionarMedicos', [PersonaController::class,'mostrarMedicos'])->name('personaMostrarMedicos')->middleware('auth','firstLogin','role:administrador');
这是我的中间件的代码(在路由中称为路由)
<?php
namespace App\Http\Middleware;
use Closure;
use Illuminate\Http\Request;
class EnsureUserHasRole
/**
* Handle an incoming request.
*
* @param \Illuminate\Http\Request $request
* @param \Closure $next
* @return mixed
*/
public function handle(Request $request, Closure $next, $role)
if (! $request->user()->hasRole($role))
// Redirect...
return back();
return $next($request);
这是用户模型的代码
<?php
namespace App\Models;
use Illuminate\Contracts\Auth\MustVerifyEmail;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;
use Illuminate\Database\Eloquent\Model;
class User extends Authenticatable
use HasFactory, Notifiable;
/**
* The attributes that are mass assignable.
*
* @var array
*/
protected $fillable = [
'role',
'name',
'email',
'password',
'idPersona',
'estado'
];
public function Persona()
return $this->belongsTo(Persona::class,'idPersona');
/**
* The attributes that should be hidden for arrays.
*
* @var array
*/
protected $hidden = [
'remember_token'
];
/**
* The attributes that should be cast to native types.
*
* @var array
*/
protected $casts = [
'email_verified_at' => 'datetime',
];
public function hasRole($role)
return User::where('role', $role)->get();
某些逻辑没有正确完成,因为即使没有该角色的用户我也可以访问路由
中间件中的 dd() 用于测试,我得到了“管理员”。
我已经尝试了 Patrick Obafemi 的解决方案,但我仍然遇到同样的问题。
为了测试,我根据 Patrcik 的回答结果做了一个 dd 判断,结果是假的。
我不确定逻辑问题在哪里。
如果对我有帮助,我还将发布我的数据库模型的图片。
【问题讨论】:
dd($role);你来这里做什么? 'administrador' 忘记删除有问题的,我用它来测试。将添加问题 【参考方案1】:问题在下面的链接中得到解答。
Middleware doesn't protect routes based on role
它还介绍了在需要为多个角色执行此操作的情况下如何保护路由。该条件是错误的,因为它提供了具有管理员角色的用户的集合。条件应该是这样的,只允许期望的角色访问路由
if (!$request->user() || $request->user()->role != $role)
// Redirect...
return back();
对于多个角色,您可以访问答案说明如何允许多个所需角色访问路由的链接。
也许帕特里克的回答是正确的,但这里也回答了问题。
【讨论】:
我是提出这个问题并在我提供的链接中再次提问的人,并且首先在这里得到了正确的回答。现在我将在这里尝试更详细一点,但链接中的答案提供了完美的答案。【参考方案2】:我认为您的错误来自用户模型中的 hasRole。结果 user() 已经可以访问您的用户模型,因此您可以将其设置为本地范围。您现在在中间件中执行的操作将返回类似这样的内容。因此,使用 get 函数将返回用户集合,但要检查该用户是否存在,您应该使用 first() 或者更好的是仍然存在()。您也不能在单个模型实体上调用 where ,这就是 $request->user()->role() 试图做的事情
User::User::where('role', $role)->get();
试试这个
<?php
namespace App\Http\Middleware;
use Closure;
use Illuminate\Http\Request;
class EnsureUserHasRole
/**
* Handle an incoming request.
*
* @param \Illuminate\Http\Request $request
* @param \Closure $next
* @return mixed
*/
public function handle(Request $request, Closure $next, $role)
$id = $request->user()->id;
if (!User::where([['id', $id],['role',$role]])->exists())
// Redirect...
return back();
return $next($request);
那么你的模型会是这样的
<?php
namespace App\Models;
use Illuminate\Contracts\Auth\MustVerifyEmail;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;
use Illuminate\Database\Eloquent\Model;
class User extends Authenticatable
use HasFactory, Notifiable;
/**
* The attributes that are mass assignable.
*
* @var array
*/
protected $fillable = [
'role',
'name',
'email',
'password',
'idPersona',
'estado'
];
public function Persona()
return $this->belongsTo(Persona::class,'idPersona');
/**
* The attributes that should be hidden for arrays.
*
* @var array
*/
protected $hidden = [
'remember_token'
];
/**
* The attributes that should be cast to native types.
*
* @var array
*/
protected $casts = [
'email_verified_at' => 'datetime',
];
public function scopeRole($query, $role)
return $query->where('role', $role);
【讨论】:
我尝试复制您的代码,但它不起作用 将尝试用所发生的情况更新问题。 @DiegoUtreras 你已经解决了吗?因为我明白为什么你的代码不起作用。我会更新我的答案 已经在这里解决了。 ***.com/questions/69231478/…【参考方案3】:甚至你的类图也有问题。如果有角色,那么应该有继承。你已经在这里如何实现这一点了。简而言之,解决方案是制作门或策略或中间件。我有一个中间件示例,但仅用于验证用户是否为管理员。
class VerifyIsAdmin
public function handle($request, Closure $next)
$user = $request->user();
if ($user && $user->role === 'admin')
return $next($request);
return abort(403);
这涉及 verifyIsAdmin 中间件。然后你去
APP/Http/Kernel
然后粘贴
protected $routeMiddleware = [
'admin' => VerifyIsAdmin::class,
];
并在命名空间中添加以下行
use App\Http\Middleware\VerifyIsAdmin;
并添加到路由组
Route::middleware(['admin'])->group(function ()
【讨论】:
以上是关于无法基于角色 Laravel 8 保护路由的主要内容,如果未能解决你的问题,请参考以下文章