Laravel中使用多态关联来实现权限自动分配和回收
1、Laravel的Eloquent ORM提供了多态关联的功能,这意味着我们可以将多个不同的模型与同一组数据进行关联。这对实现权限自动分配和回收非常有用。
例如,假设我们需要对我们的应用程序中的“文章”和“评论”进行权限控制以及对用户进行分配角色。我们可以创建以下四个模型:
User(用户)
Article(文章)
Comment(评论)
Role(角色)
然后,我们可以使用多态关联功能来将三个模型与角色进行关联:
class User extends Model
{
public function roles()
{
return $this->morphToMany(Role::class, 'model', 'model_has_roles');
}
}
class Article extends Model
{
public function roles()
{
return $this->morphToMany(Role::class, 'model', 'model_has_roles');
}
}
class Comment extends Model
{
public function roles()
{
return $this->morphToMany(Role::class, 'model', 'model_has_roles');
}
}
该例子使用了Laravel的多态关联功能,使得我们可以在三个模型以及它们的记录上定义角色关系。下一步是创建一个中间表来保存这些关系:
class CreateModelHasRolesTable extends Migration
{
public function up()
{
Schema::create('model_has_roles', function (Blueprint $table) {
$table->unsignedBigInteger('role_id');
$table->unsignedBigInteger('model_id');
$table->string('model_type');
$table->foreign('role_id')->references('id')->on('roles')->onDelete('cascade');
$table->primary(['role_id', 'model_id', 'model_type']);
});
}
}
现在我们可以将上述模型与相应的角色相关联了。例如,假设我们将“作者”角色分配给文章的创建者,我们可以这样做:
$article->roles()->syncWithoutDetaching([
Role::where('name', 'author')->first()->id
]);
同样地,创建一个新评论并将“评论者”角色分配给该评论的创建者,可以这样实现:
$comment = new Comment();
$comment->content = 'This is a new comment.';
$comment->user_id = Auth::user()->id;
$comment->save();
$comment->roles()->syncWithoutDetaching([
Role::where('name', 'commenter')->first()->id
]);
这样的代码允许我们使用角色来控制谁可以执行哪些操作。现在,我们需要一个方式来自动为新用户和他们的文章和评论分配适当的角色,并在这些记录被删除时自动删除角色分配。
2、使用Laravel中的事件监听器来实现权限自动分配和回收
为了实现权限自动分配和回收,我们使用Laravel事件系统中的事件监听器来捕获我们感兴趣的事件。事件监听器是一种注册了应用程序特定事件响应功能的机制,这个机制使得我们能够非常灵活地对应用程序的不同事件做出响应。
例如,Laravel提供了UserCreating和UserDeleting事件,这些事件在创建和删除用户时自动触发。我们可以写一个事件监听器来在用户创建时创建所需的角色关系,并在它删除时删除此关系。
首先,我们需要定义一个新的事件监听器:
class UserEventListener
{
public function onUserCreating(UserCreating $event)
{
$user = $event->user;
$roles = Role::where('name', 'user')->get();
foreach ($roles as $role) {
$user->roles()->create([
'role_id' => $role->id,
]);
}
}
public function onUserDeleting(UserDeleting $event)
{
$user = $event->user;
$user->roles()->detach();
}
}
此事件监听器定义了两个方法。一个方法(onUserCreating)在用户创建时自动触发,并将“用户”角色分配给该用户。另一个方法(onUserDeleting)在用户删除时自动触发,并删除与该角色相关的所有记录。
接下来,我们需要在我们的应用程序服务提供者中注册这些事件监听器:
class AppServiceProvider extends ServiceProvider
{
protected $listen = [
UserCreating::class => [
UserEventListener::class,
],
UserDeleting::class => [
UserEventListener::class,
],
];
public function boot()
{
//
}
}
现在,当我们创建或删除用户时,将自动执行适当的操作。安装角色的最后一步是为文章和评论定义一个类似的事件监听器。
class ArticleEventListener
{
public function onArticleCreating(ArticleCreating $event)
{
$article = $event->article;
$roles = Role::where('name', 'author')->get();
foreach ($roles as $role) {
$article->roles()->create([
'role_id' => $role->id,
]);
}
}
public function onArticleDeleting(ArticleDeleting $event)
{
$article = $event->article;
$article->roles()->detach();
}
}
class CommentEventListener
{
public function onCommentCreating(CommentCreating $event)
{
$comment = $event->comment;
$roles = Role::where('name', 'commenter')->get();
foreach ($roles as $role) {
$comment->roles()->create([
'role_id' => $role->id,
]);
}
}
public function onCommentDeleting(CommentDeleting $event)
{
$comment = $event->comment;
$comment->roles()->detach();
}
}
我们同样需要在服务提供者中将这些监听器注册为相应的事件:
class AppServiceProvider extends ServiceProvider
{
protected $listen = [
UserCreating::class => [
UserEventListener::class,
],
UserDeleting::class => [
UserEventListener::class,
],
ArticleCreating::class => [
ArticleEventListener::class,
],
ArticleDeleting::class => [
ArticleEventListener::class,
],
CommentCreating::class => [
CommentEventListener::class,
],
CommentDeleting::class => [
CommentEventListener::class,
],
];
public function boot()
{
//
}
}
现在,我们已经完成了实现权限自动分配和回收的全部步骤。在此之后,我们再创建用户、文章或评论时,将自动分配对应的角色。在删除这些记录时,我们将自动从相关的角色中删除它们。