Laravel 编码教程:自己写一个用户角色系统

Laravel

TL;DR(Too Long; Didn't Read的缩写)

注意: 通过  Role::wrap 方法,您可以在数据库中“随时随地”的创建角色。因此,无需为您的数据库添加角色即可开始使用它们。如果您仍然希望使用角色为数据库设置种子数据,请使用方法Role::fromArray(['admin', 'vip', 'guest'])

// 在路由上使用:
Route::get('admin', 'AdminController@index')->middleware('role:admin');

// 为用户增加一个角色:
$user->addRole('admin');

// 移除用户某个角色:
$user->removeRole('admin');

// 选择具有`admin`角色的用户:
User::whereRole('admin')->get();

// 获取用户的角色:
$user->roles;   // Collection
$user->roles(); // Query Builder

判断用户是否具有角色:

// 如果用户具有“admin”角色,则为true;否则为false。
$user->hasRole('admin'); 

//如果用户具有“guest”或“vip”(或两者兼有)角色,则为true,否则为false。
$user->hasAnyRole('guest', 'vip'); 

// 如果用户同时具有“admin”和“accounting”角色,则为true;否则为false。
$user->hasRoles('admin', 'accounting'); 

实现

1. 迁移

运行: php artisan make:migration create_roles_table --create=roles

使用以下内容填充:

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

class CreateRolesTable extends Migration
{
    public function up()
    {
        Schema::create('roles', function (Blueprint $table) {
            $table->bigIncrements('id');
            $table->string('name')->unique();
            $table->string('description')->nullable();
            $table->timestamps();
        });
    }

    public function down()
    {
        Schema::dropIfExists('roles');
    }
}

运行: php artisan make:migration create_role_user_table --create=role_user

使用以下内容填充:

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

class CreateRoleUserTable extends Migration
{
    public function up()
    {
        Schema::create('role_user', function (Blueprint $table) {
            $table->bigIncrements('id');
            $table->foreignId('user_id');
            $table->foreignId('role_id');
            $table->timestamps();

            $table->foreign('user_id')
                ->references('id')->on('users')
                ->onDelete('cascade')->onUpdate('cascade');

            $table->foreign('role_id')
                ->references('id')->on('roles')
                ->onDelete('cascade')->onUpdate('cascade');
        });
    }

    public function down()
    {
        Schema::dropIfExists('role_user');
    }
}

2.模型 与 Traits

运行: php artisan make:model Role

使用以下内容填充:

namespace App;

use App\HasName;
use Illuminate\Database\Eloquent\Model;

class Role extends Model
{
    use HasName;

    protected $fillable = [
        'name',
        'description',
    ];

    public function users()
    {
        return $this->belongsToMany(User::class);
    }
}

创建文件 app/Concerns/HasName.php

使用以下内容填充:

namespace App;

use Illuminate\Database\Eloquent\ModelNotFoundException;
use Illuminate\Support\Collection;

trait HasName
{
    public static function findFromName(string $name): self
    {
        return self::whereName($name)->firstOrFail();
    }

    public static function findOrCreate(string $name, string $description = ""): self
    {
        try {
            return self::findFromName($name);
        } catch (ModelNotFoundException $e) {
            return self::create(compact('name'));
        }
    }

    public static function wrap($name): self
    {
        if (is_string($name)) {
            $name = self::findOrCreate($name);
        }

        if (is_array($name)) {
            $name = self::firstOrCreate($name);
        }

        if (! $name instanceof self) {
            throw new \InvalidArgumentException("\$name should be string, array, or " . self::class);
        }

        return $name;
    }

    public static function fromArray(array $array): Collection
    {
        return (new Collection($array))->map(fn($item) => self::wrap($item));
    }
}

创建文件 app/Concerns/HasRoles.php

文件代码:

namespace App;

use App\Role;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Support\Arr;
use Illuminate\Support\Facades\DB;

trait HasRoles
{
    public function roles()
    {
        return $this->belongsToMany(Role::class);
    }

    public function hasRole($role): bool
    {
        return $this->roles()->get()->contains(Role::wrap($role));
    }

    public function hasRoles(...$roles): bool
    {
        foreach (Arr::flatten($roles) as $role) {
            if (! $this->hasRole($role)) {
                return false;
            }
        }

        return true;
    }

    public function hasAnyRole(...$roles): bool
    {
        foreach (Arr::flatten($roles) as $role) {
            if ($this->hasRole($role)) {
                return true;
            }
        }

        return false;
    }

    public function addRole($role): void
    {
        $this->roles()->attach(Role::wrap($role));
    }

    public function removeRole($role): void
    {
        $this->roles()->detach(Role::wrap($role));
    }

    public function scopeWhereRole(Builder $query, $role): Builder
    {
        return $query->whereHas('roles', function($query) use ($role) {
            return $query->where(DB::raw('"roles"."id"'), Role::wrap($role)->id)
        });
    }
}

将此添加到 app/User.php

namespace App;

use App\Concerns;

class User
{
    use Concerns\HasRoles;
}

3. 中间件

Create a new file app/Http/Middleware/Role.php

文件代码如下:

namespace App\Http\Middleware;

use Illuminate\Auth\Access\AuthorizationException;

class Role
{
    public function handle($request, \Closure $next)
    {
        $roles = array_slice(func_get_args(), 2);

        if (! $request->user()->hasAnyRole($roles)) {
            throw new AuthorizationException("You don't have the required role to access this resource.");
        }

        return $next($request);
    }
}

更新 app/Http/Kernel.php

protected $routeMiddleware = [
    'role' => \App\Http\Middleware\Role::class,
];
本文中的所有译文仅用于学习和交流目的,转载请务必注明文章译者、出处、和本文链接
我们的翻译工作遵照 CC 协议,如果我们的工作有侵犯到您的权益,请及时联系我们。

原文地址:https://dev.to/bdelespierre/how-to-imple...

译文地址:https://learnku.com/laravel/t/46840

本文为协同翻译文章,如您发现瑕疵请点击「改进」按钮提交优化建议
《L05 电商实战》
从零开发一个电商项目,功能包括电商后台、商品 & SKU 管理、购物车、订单管理、支付宝支付、微信支付、订单退款流程、优惠券等
《G01 Go 实战入门》
从零开始带你一步步开发一个 Go 博客项目,让你在最短的时间内学会使用 Go 进行编码。项目结构很大程度上参考了 Laravel。
讨论数量: 1

namespace App;

use App\Concerns;

class User { use Concerns\HasRoles; }

这段代码没有看懂,到底什么意思!

3年前 评论

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!