Skip to content

Commit

Permalink
🐛修复用户创建和编辑时的越权问题
Browse files Browse the repository at this point in the history
  • Loading branch information
celaraze committed Dec 20, 2023
1 parent 4516d06 commit fe48ae6
Show file tree
Hide file tree
Showing 21 changed files with 252 additions and 50 deletions.
22 changes: 22 additions & 0 deletions app/Filament/Actions/UserAction.php
Original file line number Diff line number Diff line change
Expand Up @@ -133,4 +133,26 @@ public static function delete(): Action
}
});
}

/**
* 永久删除按钮.
*/
public static function forceDelete(): Action
{
return Action::make('永久删除')
->icon('heroicon-s-trash')
->color('danger')
->requiresConfirmation()
->modalDescription('永久删除后无法恢复!')
->action(function (User $user) {
try {
$user->service()->forceDelete();
NotificationUtil::make(true, '已永久删除用户');
} catch (Exception $exception) {
LogUtil::error($exception);
NotificationUtil::make(false, $exception);
}
})
->closeModalByClickingAway(false);
}
}
35 changes: 28 additions & 7 deletions app/Filament/Forms/UserForm.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,13 @@

namespace App\Filament\Forms;

use App\Models\User;
use App\Services\RoleService;
use Awcodes\Shout\Components\Shout;
use Filament\Forms\Components\FileUpload;
use Filament\Forms\Components\Select;
use Filament\Forms\Components\TextInput;
use Illuminate\Database\Eloquent\Builder;
use Livewire\Features\SupportFileUploads\TemporaryUploadedFile;
use Ramsey\Uuid\Uuid;

Expand All @@ -24,6 +27,12 @@ public static function create(): array
->label('邮箱')
->rules(['email'])
->required(),
Select::make('roles')
->label('角色')
->multiple()
->options(RoleService::pluckOptions())
->searchable()
->preload(),
Shout::make('')
->color('warning')
->content('新建用户的默认密码为 cat ,请提醒用户及时修改密码。'),
Expand All @@ -37,18 +46,30 @@ public static function edit(): array
{
return [
TextInput::make('name')
->label('名称')
->required(),
->required()
->label('名称'),
TextInput::make('email')
->label('邮箱')
->rules(['email'])
->required(),
->required()
->label('邮箱'),
// 排除超级管理员角色
Select::make('roles')
->label('角色')
->multiple()
->relationship('roles', 'name')
->relationship(
name: 'roles',
titleAttribute: 'name',
modifyQueryUsing: function (Builder $query) {
/* @var User $auth_user */
$auth_user = auth()->user();
if (! $auth_user->is_super_admin()) {
return $query->where('id', '!=', 1);
}
},
)
->searchable()
->preload(),
->preload()
->default('roles')
->label('角色'),
];
}

Expand Down
6 changes: 4 additions & 2 deletions app/Filament/Imports/DeviceImporter.php
Original file line number Diff line number Diff line change
Expand Up @@ -27,10 +27,12 @@ public static function getColumns(): array
->example('工作站 A 组 1 号机')
->label('名称'),
ImportColumn::make('sn')
->example('AAAAAAA')
->requiredMapping()
->example('如果没有序列号,请直接填写:无。但不能留空或缺少本字段。')
->label('序列号'),
ImportColumn::make('specification')
->example('1U 2C 4GB')
->requiredMapping()
->example('如果没有规格,请直接填写:无。但不能留空或缺少本字段。')
->label('规格'),
ImportColumn::make('image')
->example('https://test.com/logo.png')
Expand Down
62 changes: 53 additions & 9 deletions app/Filament/Resources/UserResource.php
Original file line number Diff line number Diff line change
Expand Up @@ -42,8 +42,19 @@ public static function getRecordSubNavigation(Page $page): array
View::class,
Edit::class,
];
$can_update_user = auth()->user()->can('update_user');
if (! $can_update_user) {
/* @var User $user */
$user = $page->getWidgetData()['record'];
/* @var User $auth_user */
$auth_user = auth()->user();
$can_update_user = $auth_user->can('update_user');
$is_deleted = $user->service()->isDeleted();
// 先判断权限符合以及是否是已删除用户
if (! $can_update_user || $is_deleted) {
unset($navigation_items[2]);
}

// 再判断如果当前被编辑的用户是超级管理员,并且当前登录用户不是操作管理员,则不允许修改
if (isset($navigation_items[2]) && $user->is_super_admin() && ! $auth_user->is_super_admin()) {
unset($navigation_items[2]);
}

Expand Down Expand Up @@ -72,6 +83,7 @@ public static function getPermissionPrefixes(): array
'update',
'delete',
'delete_any',
'force_delete',
'import',
'export',
'reset_password',
Expand Down Expand Up @@ -110,18 +122,50 @@ public static function table(Table $table): Table
// 清除密码
UserAction::resetPassword()
->visible(function (User $user) {
$can = auth()->user()->can('reset_password_user');
// DEMO 模式不允许清除密码
$demo_mode = config('app.demo_mode');
// 有重置密码权限的用户不能互相重置,权限冲突
$is_conflict = $user->can('reset_password_user');

return $can && ! $demo_mode && ! $is_conflict;
if ($demo_mode) {
return false;
}
/* @var User $auth_user */
$auth_user = auth()->user();
if ($auth_user->is_super_admin()) {
return true;
} else {
$can = auth()->user()->can('reset_password_user');

// 有重置密码权限的用户不能互相重置,权限冲突
$is_conflict = $user->can('reset_password_user');

return $can && ! $is_conflict;
}
}),
// 删除用户
UserAction::delete()
->visible(function () {
return auth()->user()->can('delete_user');
->visible(function (User $user) {
if ($user->service()->isDeleted()) {
return false;
}
/* @var User $auth_user */
$auth_user = auth()->user();
// 超级管理员不允许删除自己,只能由其它超级管理员删除
if ($auth_user->is_super_admin() && $user->getKey() != $auth_user->getKey()) {
return true;
} else {
$can = auth()->user()->can('reset_password_user');

// 有重置密码权限的用户不能互相重置,权限冲突
$is_conflict = $user->can('reset_password_user');

return $can && ! $is_conflict;
}
}),
// 永久删除.
UserAction::forceDelete()
->visible(function (User $user) {
$can = auth()->user()->can('force_delete_user');

return $can && $user->service()->isDeleted();
}),
])
->bulkActions([
Expand Down
26 changes: 26 additions & 0 deletions app/Filament/Resources/UserResource/Pages/Edit.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,10 @@
namespace App\Filament\Resources\UserResource\Pages;

use App\Filament\Resources\UserResource;
use App\Models\User;
use App\Utils\LogUtil;
use App\Utils\NotificationUtil;
use Exception;
use Filament\Notifications\Notification;
use Filament\Resources\Pages\EditRecord;
use Filament\Support\Exceptions\Halt;
Expand All @@ -20,10 +24,32 @@ public static function getNavigationLabel(): string
return '编辑';
}

// /**
// * 保存事件.
// *
// * @param bool $shouldRedirect
// * @return void
// * @throws Halt
// */
// public function save(bool $shouldRedirect = true): void
// {
// /* @var User $user */
// $user = $this->getRecord();
// try {
// $user->service()->update($this->data);
// NotificationUtil::make(true, '保存成功');
// } catch (Exception $exception) {
// LogUtil::error($exception);
// NotificationUtil::make(false, $exception);
// $this->halt();
// }
// }

/**
* 表单保存前事件.
*
* @throws Halt
* @throws Exception
*/
protected function mutateFormDataBeforeSave(array $data): array
{
Expand Down
2 changes: 0 additions & 2 deletions app/Models/Role.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,6 @@

class Role extends \Spatie\Permission\Models\Role
{
const SUPER_ADMIN_ID = 1;

/**
* 模型到服务.
*/
Expand Down
8 changes: 8 additions & 0 deletions app/Models/User.php
Original file line number Diff line number Diff line change
Expand Up @@ -85,4 +85,12 @@ public function approvalNodes(): HasMany
{
return $this->hasMany(FlowHasNode::class, 'user_id', 'id');
}

/**
* 当前用户是否是超级管理员.
*/
public function is_super_admin(): bool
{
return $this->hasRole(1);
}
}
2 changes: 1 addition & 1 deletion app/Providers/Filament/AdminPanelProvider.php
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ public function panel(Panel $panel): Panel
->label('去 Github 为作者点赞 🌟')
->url('https://github.com/celaraze/cat')
->openUrlInNewTab()
->icon('heroicon-s-code-square'),
->icon('heroicon-s-star'),
MenuItem::make()
->label('官方文档')
->url('https://github.com/celaraze/cat/wiki')
Expand Down
2 changes: 1 addition & 1 deletion app/Services/DeviceService.php
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ public function create(array $data): void
}
$this->model->setAttribute('asset_number', $asset_number);
$this->model->setAttribute('category_id', $data['category_id']);
$this->model->setAttribute('name', $data['name']);
$this->model->setAttribute('name', $data['name'] ?? '无');
$this->model->setAttribute('brand_id', $data['brand_id']);
$this->model->setAttribute('sn', $data['sn'] ?? '无');
$this->model->setAttribute('specification', $data['specification'] ?? '无');
Expand Down
10 changes: 9 additions & 1 deletion app/Services/RoleService.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
namespace App\Services;

use App\Models\Role;
use App\Models\User;
use App\Traits\HasFootprint;
use Illuminate\Support\Collection;

Expand All @@ -22,6 +23,13 @@ public function __construct(?Role $role = null)
*/
public static function pluckOptions(): Collection
{
return Role::query()->pluck('name', 'id');
$roles = Role::query();
/* @var User $auth_user */
$auth_user = auth()->user();
if ($auth_user->is_super_admin()) {
$roles = $roles->whereNotIn('id', [1]);
}

return $roles->pluck('name', 'id');
}
}

0 comments on commit fe48ae6

Please sign in to comment.