中间件不根据角色保护路由
Middleware doesn't protect routes based on role
我几个小时前提出了一个类似的问题,但没有收到太多答案,所以这就是我问同样问题的原因,但我会尝试用不同的措辞来表达它,也许让它更清楚,我只得到该问题的一个答案,但没有用。如果你想看的话,我会把 link 加到我之前的问题中。
Can't protect Routes based on role Laravel 8
我遇到的问题是,我正在尝试使用中间件来允许访问某些路由,前提是它们具有相应的角色。
我的中间件代码是这样的(在我上一个问题的答案中建议的那个)。
<?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()->role($role)->get()) {
// 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);
}
}
不确定它是否可以帮助我的用户 table 在我的数据库中它是这样的
CREATE TABLE `users` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`role` varchar(20) DEFAULT NULL,
`name` varchar(100) DEFAULT NULL,
`email` varchar(100) DEFAULT NULL,
`password` varchar(250) DEFAULT NULL,
`created_at` datetime DEFAULT NULL,
`updated_at` datetime DEFAULT NULL,
`remember_token` varchar(255) DEFAULT NULL,
`idPersona` int(11) DEFAULT NULL,
`estado` tinyint(1) NOT NULL DEFAULT 31,
`prueba` varchar(100) DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `users_FK` (`idPersona`),
CONSTRAINT `users_FK` FOREIGN KEY (`idPersona`) REFERENCES `personas` (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=48 DEFAULT CHARSET=utf8mb4
我正在用这条路由测试我的中间件,在这种情况下,我试图只让 administrador
访问该路由,如果没有,则只允许 return。 (中间件角色就是上面代码中的那个)
Route::get('/gestionarMedicos', [PersonaController::class,'mostrarMedicos'])->name('personaMostrarMedicos')->middleware('auth','firstLogin','role:administrador');
问题是所有用户都可以访问它。我认为这是一个逻辑问题,因为如果我在 if false
之外显示带有 dd() 的 if returns,即使在 administrador
角色中也是如此。
将您的中间件方法更改为:
public function handle(Request $request, Closure $next, $role)
{
// dd($request->user()->role, $role);
// uncomment this for testing purpose if it's not working, both should be equal to "administrator"
if (!$request->user() || $request->user()->role != $role) {
// Redirect...
return back();
}
return $next($request);
}
您之前拥有的 $request->user()->role($role)->get()
将 return 管理员集合。
这不是您要找的。您只想检查当前用户 $request->user()
是否是管理员。
由于用户有一个 role
列,只需检查您提供的 $role
是否相同就足够了。
在英语中,if 语句表示“如果没有用户或用户的列 role
的值不等于 $role
,则重定向回来”。
如果您需要多个角色怎么办?
使用可变参数函数 (https://www.php.net/manual/en/functions.arguments.php#functions.variable-arg-list)。
在函数声明中添加...
(...$roles
) :
public function handle(Request $request, Closure $next, ...$roles)
{
//dd($roles);
//is now an array with all the roles you provided to the route.
if (!$request->user() || !in_array($request->user()->role, $roles)) {
// Redirect...
return back();
}
return $next($request);
}
使用可变参数函数可以将字符串参数转换为数组。
在您的路线中,您现在可以添加多个角色:
Route::get('/gestionarMedicos', [PersonaController::class,'mostrarMedicos'])->name('personaMostrarMedicos')->middleware('auth','firstLogin','role:administrador,client,somethingelse');
在中间件中,$roles
将等于:
['administrador', 'client', 'somethingelse']
我几个小时前提出了一个类似的问题,但没有收到太多答案,所以这就是我问同样问题的原因,但我会尝试用不同的措辞来表达它,也许让它更清楚,我只得到该问题的一个答案,但没有用。如果你想看的话,我会把 link 加到我之前的问题中。
Can't protect Routes based on role Laravel 8
我遇到的问题是,我正在尝试使用中间件来允许访问某些路由,前提是它们具有相应的角色。
我的中间件代码是这样的(在我上一个问题的答案中建议的那个)。
<?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()->role($role)->get()) {
// 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);
}
}
不确定它是否可以帮助我的用户 table 在我的数据库中它是这样的
CREATE TABLE `users` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`role` varchar(20) DEFAULT NULL,
`name` varchar(100) DEFAULT NULL,
`email` varchar(100) DEFAULT NULL,
`password` varchar(250) DEFAULT NULL,
`created_at` datetime DEFAULT NULL,
`updated_at` datetime DEFAULT NULL,
`remember_token` varchar(255) DEFAULT NULL,
`idPersona` int(11) DEFAULT NULL,
`estado` tinyint(1) NOT NULL DEFAULT 31,
`prueba` varchar(100) DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `users_FK` (`idPersona`),
CONSTRAINT `users_FK` FOREIGN KEY (`idPersona`) REFERENCES `personas` (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=48 DEFAULT CHARSET=utf8mb4
我正在用这条路由测试我的中间件,在这种情况下,我试图只让 administrador
访问该路由,如果没有,则只允许 return。 (中间件角色就是上面代码中的那个)
Route::get('/gestionarMedicos', [PersonaController::class,'mostrarMedicos'])->name('personaMostrarMedicos')->middleware('auth','firstLogin','role:administrador');
问题是所有用户都可以访问它。我认为这是一个逻辑问题,因为如果我在 if false
之外显示带有 dd() 的 if returns,即使在 administrador
角色中也是如此。
将您的中间件方法更改为:
public function handle(Request $request, Closure $next, $role)
{
// dd($request->user()->role, $role);
// uncomment this for testing purpose if it's not working, both should be equal to "administrator"
if (!$request->user() || $request->user()->role != $role) {
// Redirect...
return back();
}
return $next($request);
}
您之前拥有的 $request->user()->role($role)->get()
将 return 管理员集合。
这不是您要找的。您只想检查当前用户 $request->user()
是否是管理员。
由于用户有一个 role
列,只需检查您提供的 $role
是否相同就足够了。
在英语中,if 语句表示“如果没有用户或用户的列 role
的值不等于 $role
,则重定向回来”。
如果您需要多个角色怎么办?
使用可变参数函数 (https://www.php.net/manual/en/functions.arguments.php#functions.variable-arg-list)。
在函数声明中添加...
(...$roles
) :
public function handle(Request $request, Closure $next, ...$roles)
{
//dd($roles);
//is now an array with all the roles you provided to the route.
if (!$request->user() || !in_array($request->user()->role, $roles)) {
// Redirect...
return back();
}
return $next($request);
}
使用可变参数函数可以将字符串参数转换为数组。
在您的路线中,您现在可以添加多个角色:
Route::get('/gestionarMedicos', [PersonaController::class,'mostrarMedicos'])->name('personaMostrarMedicos')->middleware('auth','firstLogin','role:administrador,client,somethingelse');
在中间件中,$roles
将等于:
['administrador', 'client', 'somethingelse']