attributes->get('perm') ?? ($request->route()?->defaults['perm'] ?? null); // 다중 ANY-매칭 $permsAny = $request->attributes->get('perms_any'); // perm 미지정 라우트 처리 정책 // TODO :: 초기 도입 단계: 통과. (정책에 따라 403으로 바꿔도 됨) if (! $perm && ! $permsAny) { return $next($request); // return response()->json(['success'=>false,'message'=>'권한 설정 누락','data'=>null], 403); } // 컨텍스트 확보 $tenantId = (int) app('tenant_id'); $userId = (int) app('api_user'); if (! $tenantId || ! $userId) { return response()->json(['success' => false, 'message' => '인증 또는 테넌트 정보가 없습니다.', 'data' => null], 401); } $user = UserModel::find($userId); if (! $user) { return response()->json(['success' => false, 'message' => '사용자 없음', 'data' => null], 401); } // Spatie Teams 컨텍스트 고정 app(PermissionRegistrar::class)->setPermissionsTeamId($tenantId); // 최종 판정(DENY 최우선/부서 ALLOW 포함) if ($permsAny) { foreach ($permsAny as $p) { if (AccessService::allows($user, $p, $tenantId, 'api')) { return $next($request); } } return response()->json(['success' => false, 'message' => '권한이 없습니다.', 'data' => null], 403); } if (! AccessService::allows($user, $perm, $tenantId, 'api')) { return response()->json(['success' => false, 'message' => '권한이 없습니다.', 'data' => null], 403); } return $next($request); } }