【问题标题】:Can't protect Routes based on role Laravel 8无法基于角色 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' 忘记删除有问题的,我用它来测试。将添加问题

标签: laravel routes laravel-8 middleware


【解决方案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 你已经解决了吗?因为我明白为什么你的代码不起作用。我会更新我的答案
  • 已经在这里解决了。 stackoverflow.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 () {

【讨论】:

    猜你喜欢
    • 2017-05-10
    • 2018-06-28
    • 2021-07-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-07-18
    • 2015-04-07
    • 2016-06-12
    相关资源
    最近更新 更多