Gate Define 不适用于 role_id 为 1 的其他用户

Gate Define not working for other users except whose role_id is 1

当用户具有 role_id 1 时,中间件中的以下代码工作正常,当我在角色-> 权限上执行 dd 时,我得到的响应是数组。

但是在这条中间件线上

if (in_array($role->permissions, $permission)) {

对于 role_id 不同的所有其他用户,我收到此错误

in_array(): 参数 #2 ($haystack) 必须是数组类型,在传递数组的地方给定字符串

我的角色模型有

protected $casts = [
        'permissions' => 'array',
    ];

我的用户模型有

protected function role()
    {
        return $this->hasOne(Roles::class, 'id', 'role_id');
    }

我的 web 中间件组有

\App\Http\Middleware\RolePermissionCheck::class,

我的 Meddlware 有

namespace App\Http\Middleware;

use Closure;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Gate;


class RolePermissionCheck
{
    /**
     * Handle an incoming request.
     *
     * @param  \Illuminate\Http\Request  $request
     * @param  \Closure  $next
     * @return mixed
     */
    public function handle($request, Closure $next)
    {
        if (!empty(Auth::user()->role_id)) {
            $role = Auth::user()->role;

            Gate::before(
                function () {
                    if (Auth::user()->role_id === 1) {
                        return true;
                    }
                }
            );
            // dd($role->permissions);
            foreach ($role->permissions as $permission) {
                Gate::define(
                    $permission,
                    function ($role) use ($permission) {
                        if (in_array($role->permissions, $permission)) {
                            return true;
                        }
                    }
                );
            }
        }

        return $next($request);
    }
}

不要将我的答案标记为正确,因为用户 Autista_z 告诉你修复方法,我将分享一些东西以获得更好的代码,非常简单和“Laravel 方式”的东西.

正如用户 Autista_z 所说:“问题将出现在 foreach 循环中 Gate 定义。在循环的第一次迭代中(基于您的示例数组),您将有 $action = 0$roles = 'admin_role_manage'。所以门的名称将是 0。所以当然,那么 @can('admin_role_manage') 就是 false"。


因此,您正在设置或获得很多不需要的东西,或者换句话说,您可以拥有更清晰的代码(至少对于您的 Middleware class)。

如果您知道(也许您不知道),您可以 cast 将属性建模为您想要的类型,因此您可以简单地 foreach ($user_role->permissions as $role) 而不是 json_decode($user_role->permissions),但在你这样做之前你需要施放它。

所以你的模型会有一个 属性 $casts 这样的:

protected $casts = [
    'permissions' => 'array',
];

这将允许您执行 $model->permissions = ['role_1', 'role_2', ...]; 而无需执行 $model->permissions = json_encode(['role_1', 'role_2', ...]);(这也是 Laravel 处理此问题的方式)。

所以你的中间件会像这样结束:

namespace App\Http\Middleware;

use App\Models\User;
use App\Models\Roles;
use Closure;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Gate;

class RolePermissionCheck
{
    public function handle($request, Closure $next)
    {
        if ($role = Auth::user()->role)) {
            Gate::before(
                function (User $user) {
                    if ($user->role_id === '1') {
                        return true;
                    }
                }
            );

            foreach ($role->permissions as $permission) {
                Gate::define(
                    $permission,
                    function ($role) use ($permission) {
                        if (in_array($permission, $role->permissions)) {
                            return true;
                        }
                    }
                );
            }
        }

        return $next($request);
    }
}

看到我把$role->permissions as $roles的措辞改成了$role->permissions as $permission,你的role可能是“作者”,你的权限是newsletter_managebrand_logosquote_manage,等等。所以这不是角色而是权限。

还要记住,我认为您甚至可以为 foreach/define 部分编写更好的代码。