比方说,我有很多模型:用户、团体、综合体、房屋、公寓。
我想为不同的用户分配不同的权限。
例如,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
将包含 current
权限的 ID(像这样 10|35|42
),而 revisions
表将包含权限历史记录。
有好的方法吗?
使用授权服务是最好的方法:https://laravel.com/docs/5.3/authorization