mysql - laravel中如何设计多重权限?

标签 mysql laravel laravel-5

假设我有很多模型:用户、组、综合体、房屋、公寓。

我想为不同的用户分配不同的权限。

例如,group1 中的用户可以拥有以下权限(不言自明):“complex.show”、“complex.edit”

组2中的用户:“house.show”、“flat.show”、“flat.edit”

group3中的用户:“house.show”、“house.edit.1”、“house.edit.3”(这些用户可以查看所有房屋并可以编辑id为1和3的房屋)

迁移

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

class CreateUsersTable extends Migration
{
    public function up()
    {
        Schema::create('app_users', function (Blueprint $table) {
            $table->increments('id');
            $table->string('email')->unique();
            $table->string('first_name');
            $table->string('last_name');
            $table->string('password');
            $table->rememberToken();
            $table->boolean('active')->default(0);
            $table->string('timezone')->default('Europe/Moscow');
            $table->timestamp('created_at')->useCurrent();
            $table->timestamp('updated_at')->default(DB::raw('CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP'));
        });

        Schema::create('app_permissions', function (Blueprint $table) {
            $table->increments('id');
            $table->string('title');
            $table->string('description')->default('');
            $table->timestamp('created_at')->useCurrent();
            $table->timestamp('updated_at')->default(DB::raw('CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP'));
        });

        Schema::create('app_groups', function (Blueprint $table) {
            $table->increments('id');
            $table->string('title');
            $table->string('description')->default('');
            $table->timestamp('created_at')->useCurrent();
            $table->timestamp('updated_at')->default(DB::raw('CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP'));
        });

        Schema::create('app_group_users', function (Blueprint $table) {
            $table->integer('user_id')->unsigned();
            $table->foreign('user_id')->references('id')->on('app_users');
            $table->integer('group_id')->unsigned();
            $table->foreign('group_id')->references('id')->on('app_groups');
            $table->timestamp('created_at')->useCurrent();
            $table->timestamp('updated_at')->default(DB::raw('CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP'));
        });

        Schema::create('app_group_permissions', function (Blueprint $table) {
            $table->integer('group_id')->unsigned();
            $table->foreign('group_id')->references('id')->on('app_groups');
            $table->integer('permission_id')->unsigned();
            $table->foreign('permission_id')->references('id')->on('app_permissions');
            $table->timestamp('created_at')->useCurrent();
            $table->timestamp('updated_at')->default(DB::raw('CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP'));
        });
    }

    public function down()
    {
        Schema::dropIfExists('app_group_permissions');
        Schema::dropIfExists('app_group_users');
        Schema::dropIfExists('app_groups');
        Schema::dropIfExists('app_permissions');
        Schema::dropIfExists('app_users');
    }
}

用户模型

namespace App;

use Illuminate\Notifications\Notifiable;
use Illuminate\Foundation\Auth\User as Authenticatable;

class User extends Authenticatable
{
    use Notifiable;

    protected $table = 'app_users';

    protected $fillable = [
        'name', 'email', 'password', 'first_name', 'last_name'
    ];

    protected $visible = [
        'id', 'email', 'first_name', 'last_name', 'created_at', 'updated_at', 'timezone'
    ];

    public function groups() {
        return $this->belongsToMany('App\Group', 'app_group_users');
    }

    protected static $_PERMISSIONS_CACHE = [];

    public function permissions() {
        if(isset(self::$_PERMISSIONS_CACHE[$this->id])) {
            return self::$_PERMISSIONS_CACHE[$this->id];
        }
        $groups = $this->groups()->get();
        $_permissions = GroupPermission::whereIn('group_id', $groups)
        ->join('app_permissions', 'app_permissions.id', '=', 'app_group_permissions.permission_id')
        ->select('app_permissions.title', 'app_permissions.description')->get()->toArray();
        $permissions = [];
        foreach($_permissions as $_permission) {
            $permissions[$_permission['title']] = [
                'description' => $_permission['description']
            ];
        }
        self::$_PERMISSIONS_CACHE[$this->id] = $permissions;
        return $permissions;
    }

    protected static $_AVAILABLE_PERMISSIONS = [
        'show' => 'show', 'add' => 'add', 'edit' => 'edit', 'delete' => 'delete'
    ];
    protected static $_AVAILABLE_ENTITIES = [
        'user' => 'user', 'group' => 'group',
        'complex' => 'complex', 'house' => 'house', 'flat' => 'flat',
        'property' => 'property'
    ];

    public function has_permission($entity_permission, $id = null) {
        list($entity, $permission) = explode('.', $entity_permission);

        if(!isset(self::$_AVAILABLE_ENTITIES[$entity])) {
            throw new \InvalidArgumentException("Wrong enity '" . $entity . "'");
        }
        if(!isset(self::$_AVAILABLE_PERMISSIONS[$permission])) {
            throw new \InvalidArgumentException("Wrong permission '" . $permission . "'");
        }

        if($id !== null) {
            $entity_permission = $entity_permission . '.' . $id;
        }

        return isset($this->permissions()[$entity_permission]);
    }
}

此外,我想以这种方式存储所有权限修订(当管理员更改用户的权限时)(而不是生产代码):

\DB::transaction(function() {
    $g = App\Group::find(Input::get('group_id'));
    $p = App\Permission::find(Input::get('permission_id'));
    $permissions = $g->permissions()->lockForUpdate()->get()->pluck('id')->toArray();
    $new_permissions = array_merge($permissions, [$p->id]);
    $g->permissions()->sync($new_permissions);
    $permissions_revision = App\GroupPermissionRevision::firstOrNew(['group_id' => $g->id]);
    $permissions_revision->value = implode('|', $new_permissions);
    $permissions_revision->save();
});

这是 GroupPermissionRevision

namespace App;

use Illuminate\Database\Eloquent\Model;

class GroupPermissionRevision extends Model
{
    protected $table = 'app_group_permissions_revisions';

    use \Venturecraft\Revisionable\RevisionableTrait;

    protected $keepRevisionOf = ['value'];

    protected $fillable = ['group_id', 'value'];

}

$value 将包含当前权限的 ID(如 10|35|42)和修订表将包含权限历史记录。

这是好方法吗?

最佳答案

使用授权服务是最好的方法:https://laravel.com/docs/5.3/authorization

关于mysql - laravel中如何设计多重权限?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40827233/

相关文章:

php - MySQL 喜欢查询但不喜欢其他查询

php - 数组到 JSON 编码带有希伯来字符的奇怪行为

angularjs - Laravel - 使用 AngularJS 访问关系模型

laravel - 如何在 Netlify 上托管 Laravel 网站?

php - 从 Eloquent 关系中获取字段值

javascript - 完整日历和 Laravel 加载错误

MySql 在一条语句中查找3个表中是否存在记录

php - 使用 php 提取基本 mysql 数据

laravel - 带参数的Laravel路线

laravel - 从 5.1 升级到 Laravel 5.4.0