Laravel-将用户权限“ Gate :: Define”重构为易于阅读的代码

时间:2018-09-08 01:13:30

标签: php laravel laravel-5 laravel-authorization

所以我基本上想做的是将我的大量代码重构为更简单的东西。我在website上找到了这段代码,但我不太了解代码内部的情况。考虑到我正在使用与标准不同的策略和方法,因此我认为此代码段不起作用。

来自网站的代码段:

//PermissionsServiceProvider.php 
public function boot()
 {
     Permission::get()->map(function($permission){
        Gate::define($permission->slug, function($user) use ($permission){
           return $user->hasPermissionTo($permission);
        });
     });
 }

有人可以解释一下这段代码中到底发生了什么吗?

我的代码:

// Posts Policy
Gate::define('post.view', 'App\Policies\Blog\PostsPolicy@view');
Gate::define('post.create', 'App\Policies\Blog\PostsPolicy@create');
Gate::define('post.update', 'App\Policies\Blog\PostsPolicy@update');
Gate::define('post.delete', 'App\Policies\Blog\PostsPolicy@delete');
Gate::define('post.publish', 'App\Policies\Blog\PostsPolicy@publish');
Gate::define('post.edit', 'App\Policies\Blog\PostsPolicy@edit');
Gate::define('post.global', 'App\Policies\Blog\PostsPolicy@global');

// Categories Policy
Gate::define('category.view', 'App\Policies\Blog\CategoriesPolicy@view');
Gate::define('category.create', 'App\Policies\Blog\CategoriesPolicy@create');
Gate::define('category.update', 'App\Policies\Blog\CategoriesPolicy@update');
Gate::define('category.delete', 'App\Policies\Blog\CategoriesPolicy@delete');
Gate::define('category.edit', 'App\Policies\Blog\CategoriesPolicy@edit');
Gate::define('category.global', 'App\Policies\Blog\CategoriesPolicy@global');

// Tags Policy
Gate::define('tag.view', 'App\Policies\Blog\TagsPolicy@view');
Gate::define('tag.create', 'App\Policies\Blog\TagsPolicy@create');
Gate::define('tag.update', 'App\Policies\Blog\TagsPolicy@update');
Gate::define('tag.delete', 'App\Policies\Blog\TagsPolicy@delete');
Gate::define('tag.edit', 'App\Policies\Blog\TagsPolicy@edit');
Gate::define('tag.global', 'App\Policies\Blog\TagsPolicy@global');

// Parts Section Policy
Gate::define('part.section.view', 'App\Policies\Parts\PartSectionsPolicy@view');
Gate::define('part.section.create', 'App\Policies\Parts\PartSectionsPolicy@create');
Gate::define('part.section.update', 'App\Policies\Parts\PartSectionsPolicy@update');
Gate::define('part.section.delete', 'App\Policies\Parts\PartSectionsPolicy@delete');
Gate::define('part.section.edit', 'App\Policies\Parts\PartSectionsPolicy@edit');
Gate::define('part.section.global', 'App\Policies\Parts\PartSectionsPolicy@global');

// Parts Policy
Gate::define('part.view', 'App\Policies\Parts\PartsPolicy@view');
Gate::define('part.create', 'App\Policies\Parts\PartsPolicy@create');
Gate::define('part.update', 'App\Policies\Parts\PartsPolicy@update');
Gate::define('part.delete', 'App\Policies\Parts\PartsPolicy@delete');
Gate::define('part.edit', 'App\Policies\Parts\PartsPolicy@edit');
Gate::define('part.global', 'App\Policies\Parts\PartsPolicy@global');

// Admin Management Policy
Gate::define('admin.global', 'App\Policies\AdminManagementPolicy@global');

// User Management Policy
Gate::define('user.global', 'App\Policies\UserManagementPolicy@global');

有没有办法在我的权限表中作为foreach循环来执行此操作?这是一些伪代码:

foreach($permissions as $permission) {
    Gate::define($permission->slug, 'App\Policies\' . $permission->category . 'Policy@' . $permission->name);
}

问题:有什么方法可以使我的代码更紧凑,更易于阅读,例如网站上的代码段?

2 个答案:

答案 0 :(得分:5)

首先,该文章的作者根本没有使用策略,他创建了一个权限表,然后通过代码片段将他创建的权限绑定到了laravel gates。

 Permission::get()->map(function($permission){
    Gate::define($permission->slug, function($user) use ($permission){
       return $user->hasPermissionTo($permission);
    });
 });

让我们一行一行地打破它

Permission::get() // Query all permissions defined in permissions database table
->map(function($permission){ // Foreach permission do the following
   Gate::define($permission->slug, // Create new gate with the permission slug
   function($user) use ($permission){
      return $user->hasPermissionTo($permission); // the user table has many to many relation with permissions table, here we only check if $user is associated with $permission
   });
});

为使代码更具动态性,建议您执行以下操作:

数据库结构

  1. 创建permission数据库表

  2. 创建roles数据库表

  3. 创建permission_role数据透视表表

  4. 创建role_user数据透视表表

定义关系

  1. 角色具有许多权限(多对多关系,请使用belongsToMany进行定义)

  2. 权限属于许多角色(多对多关系,请使用belongsToMany进行定义)

  3. 用户有许多角色(多对多关系,请使用belongsToMany进行定义)

减少global权限的数量

通过使用Gate::before,您可以允许具有globalroot权限的特定用户授权所有已定义的功能:

Gate::before(function ($user, $ability) {
    if ($user->hasPermission('root-access')) {
        return true;
    }
});

如果实现数据库权限,则不再需要为每个模型创建策略,并且将使用上述代码动态定义门。

答案 1 :(得分:2)

就个人而言,您现有的代码很好。有用。这是可读的。尽管随着您的应用程序的增长,它可能变得更加冗长,但也可能没有。那为什么要改善它呢?

也就是说,这里有一些想法。您的大多数代码都是权限和策略实现之间的映射。例如,'part.view'映射到'App\Policies\Parts\PartsPolicy@view。无法删除此映射的“权重”:只能移动它。

您可以考虑将其移动到一个更简单的配置文件中,如下所示:

// config/permission-map.php
<?php return [
    'post.view' => 'App\Policies\Blog\PostsPolicy@view',
    'post.create' => 'App\Policies\Blog\PostsPolicy@create',
    'post.update' => 'App\Policies\Blog\PostsPolicy@update',
    'post.delete' => 'App\Policies\Blog\PostsPolicy@delete',
    // etc...
];

然后在启动时读取该配置并进行迭代:

// boot permissions
$permission_map = require_once('config/permission_map.php');
foreach ($permission_map as $permission => $policy_implementation) {
    Gate::define($permission, $policy_implementation);
}

优势:添加新的策略映射只会更改最重要的信息,您不必考虑如何实现这种映射-今天是Gate::define,明天也许是Sentry::policy 。此外,通过将数据与代码分离,您可以更自由地测试代码。

另一种方法可能是注释:在策略实现的DocBlock中,编写自己的注释语法,然后将其解析并编译为配置文件。遵循

namespace App\Policies\Blog;

class PostsPolicy {
    /**
     * @permission post.view
     */
    public function view() { /* ... */ }
}

我个人不喜欢这种方式:它增加了一层内部框架,我觉得很难评估其价值。