中间件不保护基于角色的路由 [英] Middleware doesn't protect routes based on role

查看:25
本文介绍了中间件不保护基于角色的路由的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我几个小时前提出了一个类似的问题,但没有收到太多答案,所以我要问同样的问题,但我会尝试用不同的方式来表达,以便更清楚地说明,我在那个问题中只得到了一个答案,但没有奏效。如果您想查看,我将为我上一个问题添加一个链接。

Can't protect Routes based on role Laravel 8

我遇到的问题是,我尝试使用中间件仅在某些路由具有各自的角色时才允许它们访问。

我的中间件代码是这样的(即我上一个问题的答案中建议的代码)。

         <?php
            
            namespace AppHttpMiddleware;
            
            use Closure;
            use IlluminateHttpRequest;
            
            class EnsureUserHasRole
            {
                /**
                 * Handle an incoming request.
                 *
                 * @param  IlluminateHttpRequest  $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 AppModels;
    
    use IlluminateContractsAuthMustVerifyEmail;
    use IlluminateDatabaseEloquentFactoriesHasFactory;
    use IlluminateFoundationAuthUser as Authenticatable;
    use IlluminateNotificationsNotifiable;
    use IlluminateDatabaseEloquentModel;
    
    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);
        }
    }

不确定它是否能提供帮助,但我的数据库中的USER表是这样的

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

我正在使用此Route测试我的中间件,在本例中,我尝试只允许administrador访问该路由,如果不允许,则返回。(中间件角色是上面代码中的角色)。

  Route::get('/gestionarMedicos', [PersonaController::class,'mostrarMedicos'])->name('personaMostrarMedicos')->middleware('auth','firstLogin','role:administrador');

问题是所有用户都可以访问它。我认为这是一个逻辑问题,因为如果我使用dd()在IF外部显示IF返回的内容,则它会显示false,即使在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()将返回管理员集合。

这不是你要找的。您只想检查当前用户$request->user()是否为管理员。

由于用户有role列,只需检查您提供的$role是否相同就足够了。

在英文中,IF语句表示";如果没有用户,或者如果用户的列role的值不等于$role,则重定向回";。


如果您需要多个角色怎么办?

使用可变函数(https://www.php.net/manual/en/functions.arguments.php#functions.variable-arg-list)。

添加...in函数声明(...$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']

这篇关于中间件不保护基于角色的路由的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆