Files
musadaq-saas/app/Middleware/CompanyAccessMiddleware.php
2026-05-06 17:10:14 +03:00

105 lines
3.3 KiB
PHP

<?php
/**
* Company Access Middleware
*
* Ensures that the current user has access to the requested company.
* - super_admin: access to ALL companies across ALL tenants
* - admin: access to ALL companies within their tenant
* - accountant: access ONLY to their assigned company (users.company_id)
* - viewer: access ONLY to their assigned company (read-only)
*
* Usage:
* $decoded = AuthMiddleware::check();
* CompanyAccessMiddleware::check($companyId, $decoded);
*/
declare(strict_types=1);
namespace App\Middleware;
use App\Core\Database;
final class CompanyAccessMiddleware
{
/**
* Check if the user can access the given company.
* Halts with 403 if access is denied.
*/
public static function check(string $companyId, array $decoded): void
{
$role = $decoded['role'] ?? '';
$tenantId = $decoded['tenant_id'] ?? '';
$userId = $decoded['user_id'] ?? '';
// super_admin can access everything
if ($role === 'super_admin') {
return;
}
$db = Database::getInstance();
// 1. Verify the company belongs to the user's tenant
$stmt = $db->prepare("SELECT id, tenant_id FROM companies WHERE id = ? LIMIT 1");
$stmt->execute([$companyId]);
$company = $stmt->fetch();
if (!$company) {
json_error('الشركة غير موجودة', 404);
}
if ($company['tenant_id'] !== $tenantId) {
// Company exists but belongs to a different tenant — treat as 404 (don't leak info)
json_error('الشركة غير موجودة', 404);
}
// 2. admin can access all companies in their tenant
if ($role === 'admin') {
return;
}
// 3. accountant / viewer — must be assigned to this specific company
$stmt = $db->prepare("SELECT company_id FROM users WHERE id = ? AND tenant_id = ? LIMIT 1");
$stmt->execute([$userId, $tenantId]);
$user = $stmt->fetch();
if (!$user || $user['company_id'] !== $companyId) {
http_response_code(403);
header('Content-Type: application/json');
echo json_encode([
'success' => false,
'message' => 'ليس لديك صلاحية للوصول إلى هذه الشركة',
'code' => 'COMPANY_ACCESS_DENIED',
], JSON_UNESCAPED_UNICODE);
exit;
}
}
/**
* Get the list of company IDs that the user can access.
* Useful for listing/filtering queries.
*/
public static function getAccessibleCompanyIds(array $decoded): ?array
{
$role = $decoded['role'] ?? '';
$tenantId = $decoded['tenant_id'] ?? '';
$userId = $decoded['user_id'] ?? '';
// super_admin & admin: null means "no filter" (access all)
if ($role === 'super_admin' || $role === 'admin') {
return null;
}
// accountant / viewer: only their assigned company
$db = Database::getInstance();
$stmt = $db->prepare("SELECT company_id FROM users WHERE id = ? AND tenant_id = ? LIMIT 1");
$stmt->execute([$userId, $tenantId]);
$user = $stmt->fetch();
if ($user && $user['company_id']) {
return [$user['company_id']];
}
return []; // No access to any company
}
}