前言
前几个月一直在折腾laravel nova,不得不说它的扩展性非常强。laravel nova packages每天都会有很多新鲜的扩展包,生态很好。spatie laravel-permission是非常不错的Role-based access control RBAC扩展包,orzlee在laravel 5.3就在使用了,这里主要说说spatie laravel-permission的laravel nova权限管理工具。
Larval nova packages
目前有三款laravel nova packages包是基于spatie laravel-permission开发的,功能上大同小异,各有特色。
1. vyuldashev/nova-permission:
这是最早出现基于spatie laravel-permission的laravel nova packages。支持自定义资源,本地化支持。
orzlee一开始也是使用的这款扩展包,但是没几天我就发现了一个问题,因为laravel nova的Relationships并不会调用spatie laravel-permission自带的权限或角色附加、分离方法,所以在给用户添加权限时不会触发权限缓存更新。这就必须等待缓存过期或者手动清理缓存。
这个问题一直没有解决,orzlee也关注了Issues:Cache not invalidated on attaching a role or permission to user好长一段时间,然而并没有进展。最后还是提问者重新创建了一个新的包insenseanalytics/laravel-nova-permission。
2. insenseanalytics/laravel-nova-permission:
这款包主要是使用ForgetCachedPermissions
中间件来判断当前路由是否为附加或分离请求(attach,detach),然后过滤出附加或分离权限的请求,执行缓存清除。
分离时没有问题,但是附加在路由判断上有点问题。orzlee在测试的时候发现附加怎么也无法清除缓存,经过调试发现url没有匹配到。
class ForgetCachedPermissions
{
/**
* Handle the incoming request.
*
* @param \Illuminate\Http\Request $request
* @param \Closure $next
*
* @return \Illuminate\Http\Response
*/
public function handle($request, $next)
{
$response = $next($request);
if ($request->is('nova-api/*/detach') ||
$request->is('nova-api/*/*/attach/*')) {
##作者判断了attach,但是orzlee的请求路由为:http://127.0.0.1:8000/nova-api/admins/1/attach-morphed/permissions
$permissionKey = (Nova::resourceForModel(app(PermissionRegistrar::class)->getPermissionClass()))::uriKey();
if ($request->viaRelationship === $permissionKey) {
app(PermissionRegistrar::class)->forgetCachedPermissions();
}
}
return $response;
}
}
orzlee已经向作者提交Issues了。
orzlee在给作者RP包语言本地化时有一个权限搜索翻译的功能没有被作者合并。作者觉得使用自定义资源功能让用户自行实现,这样也不错,不过度化设计。
权限是由开发者添加,而使用的时候基本上是管理员在操作。现在添加权限是一个搜索选择器,管理员需要给某个用户或管理员添加权限就必须搜索。权限在添加时为了多语言化必用标识,管理员在搜索时按照本地化语言搜索会方便很多。
orzlee还是把实现方法分享出来吧:
-
GuardFilterHandelTrait
主要功能是按guard_name
过滤掉不属于附加用户的权限,防止多guard_name
权限混乱。use Laravel\Nova\Http\Requests\NovaRequest; trait GuardFilterHandelTrait { /** * Override the applyFilters method to add the guard_name condition when filtering * * @param \Laravel\Nova\Http\Requests\NovaRequest $request * @param \Illuminate\Database\Eloquent\Builder $query * @param array $filters * * @return \Illuminate\Database\Eloquent\Builder */ protected static function applyFilters(NovaRequest $request, $query, array $filters) { $query = parent::applyFilters($request, $query, $filters); if ($model = head($request->__memoized)) { $guard_name = $model->guard_name ?? self::getGuardForModel(get_class($model)); $query->where('guard_name', $guard_name); } return $query; } /** * @param string model * * @return string|null */ public static function getGuardForModel(string $model) { return collect(config('auth.guards')) ->map(function ($guard) { return config("auth.providers.{$guard['provider']}.model"); })->search($model); } }
-
PermissionSearchTranslationTrait
搜索权限时会按照本地化语言反向找出对应权限。trait PermissionSearchTranslationTrait { use GuardFilterHandelTrait; /** * Override the applyFilters method,title field translation */ public function title() { return __('laravel-nova-permission::permissions.display_names.'.$this->name); } /** * Rewrite the applySearch method to apply translation field search * * @param \Illuminate\Database\Eloquent\Builder $query * @param string $search * @return \Illuminate\Database\Eloquent\Builder */ protected static function applySearch($query, $search) { return $query->where(function ($query) use ($search) { if (is_numeric($search) && in_array($query->getModel()->getKeyType(), ['int', 'integer'])) { $query->orWhere($query->getModel()->getQualifiedKeyName(), $search); } $model = $query->getModel(); $connectionType = $query->getModel()->getConnection()->getDriverName(); $likeOperator = $connectionType == 'pgsql' ? 'ilike' : 'like'; $trans_search = array_keys(preg_grep("/$search/",array_dot(__('laravel-nova-permission::permissions.display_names')))); foreach (static::searchableColumns() as $column) { $qualify_column = $model->qualifyColumn($column); foreach ($trans_search as $t_search){ $query->orWhere($qualify_column, $likeOperator, '%'.$t_search.'%'); } $query->orWhere($qualify_column, $likeOperator, '%'.$search.'%'); } }); } }
-
自定义Role & Permission资源(注意命名空间替换成自己项目对应的):
use App\Traits\Resources\GuardFilterHandelTrait; use \Insenseanalytics\LaravelNovaPermission\Role as BaseRole; class Role extends BaseRole { use GuardFilterHandelTrait; }
use App\Traits\Resources\PermissionSearchTranslationTrait; use \Insenseanalytics\LaravelNovaPermission\Permission as BasePermission; class Permission extends BasePermission { use PermissionSearchTranslationTrait; }
-
按照作者文档自定义角色和权限类:
// in app/Providers/NovaServiceProvider.php public function tools() { return [ // ... \Insenseanalytics\LaravelNovaPermission\LaravelNovaPermission::make() ->roleResource(CustomRole::class) ->permissionResource(CustomPermission::class), ]; }
-
如果你还没有发布语言文件请执行:
php artisan vendor:publish --provider="Insenseanalytics\LaravelNovaPermission\NovaPermissionServiceProvider"
创建自己本地化语言文件,例如在项目路径
./resources/lang/vendor/laravel-nova-permission/
创建一个zh-CN
文件夹,复制en
中的所有文件到zh-CN
,然后自己翻译。display_names
就是权限name
对应的本地化翻译。'display_names' => [ 'test' => '测试', 'delete' => '删除', 'edit' => '编辑', 'create' => '创建', ],
现在应该支持本地化权限搜索了。或者可以直接使用包jianminlee/laravel-nova-filter。
该包还支持基于laravel nova的权限验证,非常方便,在nova资源中使用PermissionsBasedAuthTrait
Trait,然后定义一个静态变量:
class YourNovaResource extends Resource
{
use \Insenseanalytics\LaravelNovaPermission\PermissionsBasedAuthTrait;
public static $permissionsForAbilities = [
'viewAny' => 'view products',
'view' => 'view products',
'create' => 'create products',
'update' => 'update products',
'delete' => 'delete products',
'restore' => 'restore products',
'forceDelete' => 'forceDelete products',
'addAttribute' => 'add product attributes',
'attachAttribute' => 'attach product attributes',
'detachAttribute' => 'detach product attributes',
];
....
}
详细文档可以取项目地址查看。insenseanalytics/laravel-nova-permission
3. DigitalCloud/nova-permission-tool:
今天刚刚发布的的,该包根据资源自动生成对应权限,听上去高大上,但是会多出不少多余的权限。因为我们的资源不一定会实现所有功能,到时候添加权限就会眼花缭乱了。orzlee认为还是自定义的好。
作者还自定义角色和权限的字段,在操作上体验好很多。凡是都有两面性,如果项目比较大(权限多)的情况下体验就可想而知了。
结语
这三款包都各有特色,同一功能的包就有这么多,这些还都只是基于spatie laravel-permission的,还有其他作者自己实现的权限管理工具。回过头来,还是得靠自己,工具再多也不一定都适合自己的项目,好好学Vue吧!
评论 (0)