feat(权限): 完善所有策略的权限检查
- 更新 DocumentPolicy 添加权限检查 - viewAny/view/create/update/delete/download 都检查相应权限 - 保留现有的分组访问控制逻辑 - 保留安全日志记录功能 - 更新 TerminalPolicy 添加权限检查 - 所有方法都基于 terminal.* 权限 - 新增 sync 方法用于配置同步权限检查 - 更新 SopTemplatePolicy 添加权限检查 - 所有方法都基于 sop-template.* 权限 - 保留现有的状态检查逻辑(已发布不可编辑/删除) - 创建 SystemSettingPolicy - 实现 viewAny/view/update 权限检查 - 创建 ActivityLogPolicy - 实现 viewAny/view/export 权限检查 - 创建 GroupPolicy - 实现完整的 CRUD 权限检查 - 删除前检查关联文档和用户 - 在 AppServiceProvider 中注册所有策略
This commit is contained in:
33
app/Policies/ActivityLogPolicy.php
Normal file
33
app/Policies/ActivityLogPolicy.php
Normal file
@@ -0,0 +1,33 @@
|
||||
<?php
|
||||
|
||||
namespace App\Policies;
|
||||
|
||||
use App\Models\User;
|
||||
use Spatie\Activitylog\Models\Activity;
|
||||
|
||||
class ActivityLogPolicy
|
||||
{
|
||||
/**
|
||||
* 查看操作日志列表
|
||||
*/
|
||||
public function viewAny(User $user): bool
|
||||
{
|
||||
return $user->can('activity-log.view');
|
||||
}
|
||||
|
||||
/**
|
||||
* 查看操作日志详情
|
||||
*/
|
||||
public function view(User $user, Activity $activity): bool
|
||||
{
|
||||
return $user->can('activity-log.view');
|
||||
}
|
||||
|
||||
/**
|
||||
* 导出操作日志
|
||||
*/
|
||||
public function export(User $user): bool
|
||||
{
|
||||
return $user->can('activity-log.export');
|
||||
}
|
||||
}
|
||||
@@ -24,20 +24,21 @@ class DocumentPolicy
|
||||
|
||||
/**
|
||||
* 判断用户是否可以查看文档列表
|
||||
* 所有已认证用户都可以查看文档列表(但列表会根据权限过滤)
|
||||
* 需求:权限检查 + 分组访问控制
|
||||
*
|
||||
* @param User $user
|
||||
* @return bool
|
||||
*/
|
||||
public function viewAny(User $user): bool
|
||||
{
|
||||
// 所有已认证用户都可以查看文档列表
|
||||
return true;
|
||||
// 检查用户是否有查看文档的权限
|
||||
return $user->can('document.view');
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断用户是否可以查看特定文档
|
||||
* 需求:3.1, 3.4, 7.1, 7.2, 7.3
|
||||
* 需求:3.1, 3.4, 7.1, 7.2, 7.3 + 权限检查
|
||||
* - 首先检查用户是否有 document.view 权限
|
||||
* - 全局文档:所有用户都可以查看
|
||||
* - 专用文档:只有所属分组的用户可以查看
|
||||
* - 记录未授权访问尝试
|
||||
@@ -48,6 +49,12 @@ class DocumentPolicy
|
||||
*/
|
||||
public function view(User $user, Document $document): bool
|
||||
{
|
||||
// 首先检查用户是否有查看文档的权限
|
||||
if (!$user->can('document.view')) {
|
||||
$this->securityLogger->logUnauthorizedAccess($user, $document, 'view');
|
||||
return false;
|
||||
}
|
||||
|
||||
// 如果是全局文档,所有用户都可以查看
|
||||
if ($document->type === 'global') {
|
||||
return true;
|
||||
@@ -79,21 +86,21 @@ class DocumentPolicy
|
||||
|
||||
/**
|
||||
* 判断用户是否可以创建文档
|
||||
* 假设所有已认证用户都可以创建文档(可根据实际需求调整)
|
||||
* 需求:权限检查
|
||||
*
|
||||
* @param User $user
|
||||
* @return bool
|
||||
*/
|
||||
public function create(User $user): bool
|
||||
{
|
||||
// 所有已认证用户都可以创建文档
|
||||
return true;
|
||||
return $user->can('document.create');
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断用户是否可以更新文档
|
||||
* 只有文档的上传者可以更新文档(可根据实际需求调整为管理员也可以)
|
||||
* 需求:7.3
|
||||
* 需求:7.3 + 权限检查
|
||||
* - 首先检查用户是否有 document.update 权限
|
||||
* - 只有文档的上传者可以更新文档
|
||||
*
|
||||
* @param User $user
|
||||
* @param Document $document
|
||||
@@ -101,6 +108,12 @@ class DocumentPolicy
|
||||
*/
|
||||
public function update(User $user, Document $document): bool
|
||||
{
|
||||
// 首先检查用户是否有更新文档的权限
|
||||
if (!$user->can('document.update')) {
|
||||
$this->securityLogger->logUnauthorizedAccess($user, $document, 'update');
|
||||
return false;
|
||||
}
|
||||
|
||||
// 只有文档的上传者可以更新
|
||||
$canUpdate = $document->uploaded_by === $user->id;
|
||||
|
||||
@@ -114,8 +127,9 @@ class DocumentPolicy
|
||||
|
||||
/**
|
||||
* 判断用户是否可以删除文档
|
||||
* 只有文档的上传者可以删除文档(可根据实际需求调整为管理员也可以)
|
||||
* 需求:7.3
|
||||
* 需求:7.3 + 权限检查
|
||||
* - 首先检查用户是否有 document.delete 权限
|
||||
* - 只有文档的上传者可以删除文档
|
||||
*
|
||||
* @param User $user
|
||||
* @param Document $document
|
||||
@@ -123,6 +137,12 @@ class DocumentPolicy
|
||||
*/
|
||||
public function delete(User $user, Document $document): bool
|
||||
{
|
||||
// 首先检查用户是否有删除文档的权限
|
||||
if (!$user->can('document.delete')) {
|
||||
$this->securityLogger->logUnauthorizedAccess($user, $document, 'delete');
|
||||
return false;
|
||||
}
|
||||
|
||||
// 只有文档的上传者可以删除
|
||||
$canDelete = $document->uploaded_by === $user->id;
|
||||
|
||||
@@ -136,10 +156,11 @@ class DocumentPolicy
|
||||
|
||||
/**
|
||||
* 判断用户是否可以下载文档
|
||||
* 需求:4.1, 4.2, 7.1, 7.2, 7.3
|
||||
* 下载权限与查看权限相同:
|
||||
* - 全局文档:所有用户都可以下载
|
||||
* - 专用文档:只有所属分组的用户可以下载
|
||||
* 需求:4.1, 4.2, 7.1, 7.2, 7.3 + 权限检查
|
||||
* - 首先检查用户是否有 document.download 权限
|
||||
* - 下载权限与查看权限相同:
|
||||
* - 全局文档:所有用户都可以下载
|
||||
* - 专用文档:只有所属分组的用户可以下载
|
||||
* - 记录未授权下载尝试
|
||||
*
|
||||
* @param User $user
|
||||
@@ -148,13 +169,36 @@ class DocumentPolicy
|
||||
*/
|
||||
public function download(User $user, Document $document): bool
|
||||
{
|
||||
// 下载权限与查看权限相同
|
||||
$canDownload = $this->view($user, $document);
|
||||
|
||||
// 注意:view 方法已经记录了未授权访问,这里不需要重复记录
|
||||
// 但如果需要区分 view 和 download 操作,可以在这里单独记录
|
||||
|
||||
return $canDownload;
|
||||
// 首先检查用户是否有下载文档的权限
|
||||
if (!$user->can('document.download')) {
|
||||
$this->securityLogger->logUnauthorizedAccess($user, $document, 'download');
|
||||
return false;
|
||||
}
|
||||
|
||||
// 下载权限与查看权限相同(但不需要 document.view 权限)
|
||||
// 如果是全局文档,所有用户都可以下载
|
||||
if ($document->type === 'global') {
|
||||
return true;
|
||||
}
|
||||
|
||||
// 如果是专用文档,检查用户是否属于该文档的分组
|
||||
if ($document->type === 'dedicated') {
|
||||
if (!$document->group_id) {
|
||||
$this->securityLogger->logUnauthorizedAccess($user, $document, 'download');
|
||||
return false;
|
||||
}
|
||||
|
||||
$hasAccess = $user->groups()->where('groups.id', $document->group_id)->exists();
|
||||
|
||||
if (!$hasAccess) {
|
||||
$this->securityLogger->logUnauthorizedAccess($user, $document, 'download');
|
||||
}
|
||||
|
||||
return $hasAccess;
|
||||
}
|
||||
|
||||
$this->securityLogger->logUnauthorizedAccess($user, $document, 'download');
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
72
app/Policies/GroupPolicy.php
Normal file
72
app/Policies/GroupPolicy.php
Normal file
@@ -0,0 +1,72 @@
|
||||
<?php
|
||||
|
||||
namespace App\Policies;
|
||||
|
||||
use App\Models\Group;
|
||||
use App\Models\User;
|
||||
|
||||
class GroupPolicy
|
||||
{
|
||||
/**
|
||||
* 查看分组列表
|
||||
*/
|
||||
public function viewAny(User $user): bool
|
||||
{
|
||||
return $user->can('group.view');
|
||||
}
|
||||
|
||||
/**
|
||||
* 查看分组详情
|
||||
*/
|
||||
public function view(User $user, Group $group): bool
|
||||
{
|
||||
return $user->can('group.view');
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建分组
|
||||
*/
|
||||
public function create(User $user): bool
|
||||
{
|
||||
return $user->can('group.create');
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新分组
|
||||
*/
|
||||
public function update(User $user, Group $group): bool
|
||||
{
|
||||
return $user->can('group.update');
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除分组
|
||||
*/
|
||||
public function delete(User $user, Group $group): bool
|
||||
{
|
||||
// 首先检查权限
|
||||
if (!$user->can('group.delete')) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// 检查是否有关联文档
|
||||
if ($group->documents()->count() > 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// 检查是否有关联用户
|
||||
if ($group->users()->count() > 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量删除分组
|
||||
*/
|
||||
public function deleteAny(User $user): bool
|
||||
{
|
||||
return $user->can('group.delete');
|
||||
}
|
||||
}
|
||||
@@ -12,7 +12,7 @@ class SopTemplatePolicy
|
||||
*/
|
||||
public function viewAny(User $user): bool
|
||||
{
|
||||
return true;
|
||||
return $user->can('sop-template.view');
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -20,7 +20,7 @@ class SopTemplatePolicy
|
||||
*/
|
||||
public function view(User $user, SopTemplate $sopTemplate): bool
|
||||
{
|
||||
return true;
|
||||
return $user->can('sop-template.view');
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -28,7 +28,7 @@ class SopTemplatePolicy
|
||||
*/
|
||||
public function create(User $user): bool
|
||||
{
|
||||
return true;
|
||||
return $user->can('sop-template.create');
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -36,6 +36,11 @@ class SopTemplatePolicy
|
||||
*/
|
||||
public function update(User $user, SopTemplate $sopTemplate): bool
|
||||
{
|
||||
// 首先检查权限
|
||||
if (!$user->can('sop-template.update')) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// 已发布的模板不能直接编辑
|
||||
if ($sopTemplate->status === 'published') {
|
||||
return false;
|
||||
@@ -49,6 +54,11 @@ class SopTemplatePolicy
|
||||
*/
|
||||
public function delete(User $user, SopTemplate $sopTemplate): bool
|
||||
{
|
||||
// 首先检查权限
|
||||
if (!$user->can('sop-template.delete')) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// 已发布的模板不能删除
|
||||
if ($sopTemplate->status === 'published') {
|
||||
return false;
|
||||
@@ -62,6 +72,11 @@ class SopTemplatePolicy
|
||||
*/
|
||||
public function publish(User $user, SopTemplate $sopTemplate): bool
|
||||
{
|
||||
// 首先检查权限
|
||||
if (!$user->can('sop-template.publish')) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return $sopTemplate->status === 'draft';
|
||||
}
|
||||
|
||||
@@ -70,6 +85,11 @@ class SopTemplatePolicy
|
||||
*/
|
||||
public function archive(User $user, SopTemplate $sopTemplate): bool
|
||||
{
|
||||
// 首先检查权限
|
||||
if (!$user->can('sop-template.archive')) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return $sopTemplate->status === 'published';
|
||||
}
|
||||
}
|
||||
|
||||
33
app/Policies/SystemSettingPolicy.php
Normal file
33
app/Policies/SystemSettingPolicy.php
Normal file
@@ -0,0 +1,33 @@
|
||||
<?php
|
||||
|
||||
namespace App\Policies;
|
||||
|
||||
use App\Models\SystemSetting;
|
||||
use App\Models\User;
|
||||
|
||||
class SystemSettingPolicy
|
||||
{
|
||||
/**
|
||||
* 查看系统设置列表
|
||||
*/
|
||||
public function viewAny(User $user): bool
|
||||
{
|
||||
return $user->can('system-setting.view');
|
||||
}
|
||||
|
||||
/**
|
||||
* 查看系统设置详情
|
||||
*/
|
||||
public function view(User $user, SystemSetting $systemSetting): bool
|
||||
{
|
||||
return $user->can('system-setting.view');
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新系统设置
|
||||
*/
|
||||
public function update(User $user, SystemSetting $systemSetting): bool
|
||||
{
|
||||
return $user->can('system-setting.update');
|
||||
}
|
||||
}
|
||||
@@ -15,8 +15,7 @@ class TerminalPolicy
|
||||
*/
|
||||
public function viewAny(User $user): bool
|
||||
{
|
||||
// 所有已认证用户都可以查看终端列表
|
||||
return true;
|
||||
return $user->can('terminal.view');
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -28,8 +27,7 @@ class TerminalPolicy
|
||||
*/
|
||||
public function view(User $user, Terminal $terminal): bool
|
||||
{
|
||||
// 所有已认证用户都可以查看终端详情
|
||||
return true;
|
||||
return $user->can('terminal.view');
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -40,8 +38,7 @@ class TerminalPolicy
|
||||
*/
|
||||
public function create(User $user): bool
|
||||
{
|
||||
// 所有已认证用户都可以创建终端
|
||||
return true;
|
||||
return $user->can('terminal.create');
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -53,8 +50,7 @@ class TerminalPolicy
|
||||
*/
|
||||
public function update(User $user, Terminal $terminal): bool
|
||||
{
|
||||
// 所有已认证用户都可以更新终端
|
||||
return true;
|
||||
return $user->can('terminal.update');
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -66,8 +62,19 @@ class TerminalPolicy
|
||||
*/
|
||||
public function delete(User $user, Terminal $terminal): bool
|
||||
{
|
||||
// 所有已认证用户都可以删除终端
|
||||
return true;
|
||||
return $user->can('terminal.delete');
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断用户是否可以同步终端配置
|
||||
*
|
||||
* @param User $user
|
||||
* @param Terminal $terminal
|
||||
* @return bool
|
||||
*/
|
||||
public function sync(User $user, Terminal $terminal): bool
|
||||
{
|
||||
return $user->can('terminal.sync');
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -79,8 +86,7 @@ class TerminalPolicy
|
||||
*/
|
||||
public function restore(User $user, Terminal $terminal): bool
|
||||
{
|
||||
// 所有已认证用户都可以恢复终端
|
||||
return true;
|
||||
return $user->can('terminal.delete');
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -92,7 +98,6 @@ class TerminalPolicy
|
||||
*/
|
||||
public function forceDelete(User $user, Terminal $terminal): bool
|
||||
{
|
||||
// 所有已认证用户都可以永久删除终端
|
||||
return true;
|
||||
return $user->can('terminal.delete');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -37,5 +37,8 @@ class AppServiceProvider extends ServiceProvider
|
||||
Gate::policy(SopTemplate::class, SopTemplatePolicy::class);
|
||||
Gate::policy(\Spatie\Permission\Models\Role::class, \App\Policies\RolePolicy::class);
|
||||
Gate::policy(\App\Models\User::class, \App\Policies\UserPolicy::class);
|
||||
Gate::policy(\App\Models\SystemSetting::class, \App\Policies\SystemSettingPolicy::class);
|
||||
Gate::policy(\Spatie\Activitylog\Models\Activity::class, \App\Policies\ActivityLogPolicy::class);
|
||||
Gate::policy(\App\Models\Group::class, \App\Policies\GroupPolicy::class);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user