路由权限校验

main
Jing Li 2024-03-25 09:23:47 +08:00
parent 90bd0711cf
commit 1af4a4952c
3 changed files with 166 additions and 1 deletions

View File

@ -0,0 +1,96 @@
<?php
namespace App\Admin\Middleware;
use Closure;
use Illuminate\Http\Request;
use Illuminate\Support\Collection;
use Slowlyo\OwlAdmin\Admin;
use Slowlyo\OwlAdmin\Support\Cores\Permission;
use Symfony\Component\HttpFoundation\Response;
class CheckPermission
{
/**
* @var array<int, string>
*/
protected $exceptPaths = [
//
];
/**
* @var array<int, string>
*/
protected $exceptRoutes = [
//
];
/**
* Handle an incoming request.
*
* @param \Closure(\Illuminate\Http\Request): (\Symfony\Component\HttpFoundation\Response) $next
*/
public function handle(Request $request, Closure $next): Response
{
if ($this->inExceptArray($request) || $this->checkRoutePermission($request)) {
return $next($request);
}
return Admin::response()->fail(__('admin.unauthorized'));
}
protected function checkRoutePermission(Request $request): bool
{
if (is_null($user = Admin::user())) {
return false;
}
$ability = $this->normalizeRouteAbility(
$original = $request->route()->getName()
);
return collect($ability)
->when($ability !== $original, fn (Collection $collection) => $collection->push($original))
->contains(fn ($ability) => $user->can($ability));
}
protected function normalizeRouteAbility(string $ability)
{
foreach ($this->resourceAbilityMap() as $method => $map) {
if (str_ends_with($ability, ".{$method}")) {
return preg_replace("/(.*)\.{$method}$/", '${1}.'.$map, $ability);
}
}
return $ability;
}
protected function resourceAbilityMap(): array
{
return [
'index' => 'list',
'show' => 'view',
'store' => 'create',
'edit' => 'update',
'destroy' => 'delete',
];
}
protected function inExceptArray(Request $request): bool
{
if (in_array($request->route()->getName(), $this->exceptRoutes)) {
return true;
}
$permission = Admin::permission();
return $request->is(
collect($this->exceptPaths)
->when(Admin::permission(), fn (Collection $collection, Permission $permission) => $collection->merge($permission->authExcept)->merge($permission->permissionExcept))
->map(function ($path) {
$path = trim((string) config('admin.route.prefix'), '/').'/'.trim((string) $path, '/');
return ltrim($path, '/');
})
);
}
}

View File

@ -9,11 +9,74 @@ use Slowlyo\OwlAdmin\Models\AdminUser as Model;
class AdminUser extends Model class AdminUser extends Model
{ {
/**
* @var \Illuminate\Support\Collection
*/
protected $allAbilities;
public function roles(): BelongsToMany public function roles(): BelongsToMany
{ {
return $this->belongsToMany(Admin::adminRoleModel(), 'admin_role_users', 'user_id', 'role_id')->withTimestamps(); return $this->belongsToMany(Admin::adminRoleModel(), 'admin_role_users', 'user_id', 'role_id')->withTimestamps();
} }
/**
* 获取此用户的全部能力
*/
public function allAbilities(): Collection
{
if ($this->allAbilities) {
return $this->allAbilities;
}
$model = Admin::adminPermissionModel();
$allPermissions = $model::all(['id', 'parent_id', 'slug'])->keyBy('id');
/** @var \Illuminate\Database\Eloquent\Collection 此用户的所有角色的权限集合 */
$rolePermissions = $this->roles
->pluck('permissions')
->flatten()
->keyBy('id');
$abilities = $rolePermissions->map(fn ($permission) => $permission->slug);
foreach ($rolePermissions as $rolePermission) {
if (is_null($rolePermission->parent_id) || $abilities->has($rolePermission->parent_id)) {
continue;
}
$parent = $allPermissions->get($rolePermission->parent_id);
while ($parent) {
$abilities->put($parent->id, $parent->slug);
if (is_null($parent->parent_id)) {
break;
}
$parent = $allPermissions->get($parent->parent_id);
};
}
unset($allPermissions, $rolePermissions);
return $this->allAbilities = $abilities;
}
public function can($abilities, $arguments = []): bool
{
if (empty($abilities)) {
return true;
}
if ($this->isAdministrator()) {
return true;
}
return collect($abilities)->every(
fn ($ability) => $this->allAbilities()->contains($ability)
);
}
public function allMenus(): Collection public function allMenus(): Collection
{ {
$model = Admin::adminMenuModel(); $model = Admin::adminMenuModel();

View File

@ -21,7 +21,13 @@ return [
'prefix' => 'admin-api', 'prefix' => 'admin-api',
'domain' => null, 'domain' => null,
'namespace' => 'App\\Admin\\Controllers', 'namespace' => 'App\\Admin\\Controllers',
'middleware' => ['admin'], 'middleware' => [
'admin.auth',
'admin.bootstrap',
\App\Admin\Middleware\CheckPermission::class,
'sanctum',
'substitute',
],
// 不包含额外路由, 配置后, 不会追加新增/详情/编辑页面路由 // 不包含额外路由, 配置后, 不会追加新增/详情/编辑页面路由
'without_extra_routes' => [ 'without_extra_routes' => [
'/dashboard', '/dashboard',