diff --git a/app/Services/UserPermissionService.php b/app/Services/UserPermissionService.php index 87f3195d..1fb6dbff 100644 --- a/app/Services/UserPermissionService.php +++ b/app/Services/UserPermissionService.php @@ -4,6 +4,7 @@ use App\Models\Commons\Menu; use App\Models\Permission; +use App\Models\Scopes\TenantScope; use App\Models\User; use Illuminate\Support\Facades\DB; @@ -28,8 +29,8 @@ public function getUserPermissionMatrix(int $userId, ?int $tenantId = null, stri { $now = now(); - // 1. 역할 권한 조회 (Spatie) - $rolePermissions = $this->getRolePermissions($userId, $guardName); + // 1. 역할 권한 조회 (Spatie + user_roles) + $rolePermissions = $this->getRolePermissions($userId, $guardName, $tenantId); // 2. 부서 권한 조회 (permission_overrides with Department) $departmentPermissions = $this->getDepartmentPermissions($userId, $tenantId, $guardName); @@ -93,11 +94,12 @@ public function getUserPermissionMatrix(int $userId, ?int $tenantId = null, stri } /** - * 역할 권한 조회 (Spatie model_has_roles + role_has_permissions) + * 역할 권한 조회 (Spatie model_has_roles + user_roles + role_has_permissions) */ - private function getRolePermissions(int $userId, string $guardName): array + private function getRolePermissions(int $userId, string $guardName, ?int $tenantId = null): array { - $rolePermissions = DB::table('model_has_roles as mhr') + // 1. Spatie model_has_roles 테이블에서 권한 조회 + $spatiePermissions = DB::table('model_has_roles as mhr') ->join('role_has_permissions as rhp', 'rhp.role_id', '=', 'mhr.role_id') ->join('permissions as p', 'p.id', '=', 'rhp.permission_id') ->where('mhr.model_type', User::class) @@ -107,6 +109,24 @@ private function getRolePermissions(int $userId, string $guardName): array ->pluck('p.name') ->toArray(); + // 2. user_roles 테이블에서 권한 조회 (테넌트별 역할) + $userRolesQuery = DB::table('user_roles as ur') + ->join('role_has_permissions as rhp', 'rhp.role_id', '=', 'ur.role_id') + ->join('permissions as p', 'p.id', '=', 'rhp.permission_id') + ->where('ur.user_id', $userId) + ->whereNull('ur.deleted_at') + ->where('p.guard_name', $guardName) + ->where('p.name', 'like', 'menu:%'); + + if ($tenantId) { + $userRolesQuery->where('ur.tenant_id', $tenantId); + } + + $userRolesPermissions = $userRolesQuery->pluck('p.name')->toArray(); + + // 3. 권한 통합 (중복 제거) + $rolePermissions = array_unique(array_merge($spatiePermissions, $userRolesPermissions)); + $result = []; foreach ($rolePermissions as $permName) { if (preg_match('/^menu:(\d+)\.(\w+)$/', $permName, $matches)) { @@ -258,7 +278,7 @@ public function togglePermission(int $userId, int $menuId, string $permissionTyp ->first(); // 역할/부서 권한 확인 - $hasRolePermission = $this->hasRolePermission($userId, $permissionName, $guardName); + $hasRolePermission = $this->hasRolePermission($userId, $permissionName, $tenantId, $guardName); $hasDeptPermission = $this->hasDeptPermission($userId, $permissionName, $tenantId, $guardName); $hasInheritedPermission = $hasRolePermission || $hasDeptPermission; @@ -303,11 +323,12 @@ public function togglePermission(int $userId, int $menuId, string $permissionTyp } /** - * 역할 권한 존재 여부 확인 + * 역할 권한 존재 여부 확인 (Spatie + user_roles) */ - private function hasRolePermission(int $userId, string $permissionName, string $guardName): bool + private function hasRolePermission(int $userId, string $permissionName, ?int $tenantId, string $guardName): bool { - return DB::table('model_has_roles as mhr') + // 1. Spatie model_has_roles 테이블에서 확인 + $hasSpatiePermission = DB::table('model_has_roles as mhr') ->join('role_has_permissions as rhp', 'rhp.role_id', '=', 'mhr.role_id') ->join('permissions as p', 'p.id', '=', 'rhp.permission_id') ->where('mhr.model_type', User::class) @@ -315,6 +336,25 @@ private function hasRolePermission(int $userId, string $permissionName, string $ ->where('p.guard_name', $guardName) ->where('p.name', $permissionName) ->exists(); + + if ($hasSpatiePermission) { + return true; + } + + // 2. user_roles 테이블에서 확인 + $userRolesQuery = DB::table('user_roles as ur') + ->join('role_has_permissions as rhp', 'rhp.role_id', '=', 'ur.role_id') + ->join('permissions as p', 'p.id', '=', 'rhp.permission_id') + ->where('ur.user_id', $userId) + ->whereNull('ur.deleted_at') + ->where('p.guard_name', $guardName) + ->where('p.name', $permissionName); + + if ($tenantId) { + $userRolesQuery->where('ur.tenant_id', $tenantId); + } + + return $userRolesQuery->exists(); } /** @@ -616,7 +656,10 @@ public function resetToDefaultPermissions(int $userId, ?int $tenantId = null, st */ public function getMenuTree(?int $tenantId = null): \Illuminate\Support\Collection { - $query = Menu::with('parent') + // TenantScope를 비활성화하고 명시적으로 tenant_id 필터 적용 + // (HQ 관리자가 다른 테넌트의 메뉴를 조회할 수 있도록) + $query = Menu::withoutGlobalScope(TenantScope::class) + ->with('parent') ->where('is_active', 1); if ($tenantId) { @@ -759,8 +802,8 @@ private function getUserPermissionCounts(int $userId, int $tenantId, $now): arra $result = ['web' => 0, 'api' => 0]; foreach (['web', 'api'] as $guardName) { - // 1. 역할 권한 - $rolePermissions = DB::table('model_has_roles as mhr') + // 1-1. Spatie 역할 권한 (model_has_roles) + $spatieRolePermissions = DB::table('model_has_roles as mhr') ->join('role_has_permissions as rhp', 'rhp.role_id', '=', 'mhr.role_id') ->join('permissions as p', 'p.id', '=', 'rhp.permission_id') ->where('mhr.model_type', User::class) @@ -770,6 +813,21 @@ private function getUserPermissionCounts(int $userId, int $tenantId, $now): arra ->pluck('p.name') ->toArray(); + // 1-2. 테넌트별 역할 권한 (user_roles) + $userRolesPermissions = DB::table('user_roles as ur') + ->join('role_has_permissions as rhp', 'rhp.role_id', '=', 'ur.role_id') + ->join('permissions as p', 'p.id', '=', 'rhp.permission_id') + ->where('ur.user_id', $userId) + ->where('ur.tenant_id', $tenantId) + ->whereNull('ur.deleted_at') + ->where('p.guard_name', $guardName) + ->where('p.name', 'like', 'menu:%') + ->pluck('p.name') + ->toArray(); + + // 역할 권한 통합 + $rolePermissions = array_unique(array_merge($spatieRolePermissions, $userRolesPermissions)); + // 2. 부서 권한 $deptPermissions = DB::table('department_user as du') ->join('permission_overrides as po', function ($j) use ($now, $tenantId) { diff --git a/resources/views/user-permissions/index.blade.php b/resources/views/user-permissions/index.blade.php index 1e25a117..a55e7323 100644 --- a/resources/views/user-permissions/index.blade.php +++ b/resources/views/user-permissions/index.blade.php @@ -40,9 +40,6 @@ class="user-button px-4 py-2 text-sm font-medium rounded-lg border transition-co data-user-name="{{ $user->name }}" data-user-login="{{ $user->user_id }}" data-auto-select="{{ $user->id == $autoSelectId ? 'true' : 'false' }}" - data-context-menu="user" - data-entity-id="{{ $user->id }}" - data-entity-name="{{ $user->name }}" hx-get="/api/admin/user-permissions/matrix" hx-target="#permission-matrix" hx-include="[name='guard_name']" @@ -50,7 +47,13 @@ class="user-button px-4 py-2 text-sm font-medium rounded-lg border transition-co onclick="selectUser(this)" > {{ $user->name }} -  {{ $user->user_id }}  +  {{ $user->user_id }}  @php $showWebCount = auth()->user()?->is_super_admin && $user->web_permission_count > 0; $showApiCount = $user->api_permission_count > 0;