feat(tenant): implement tenant filter scope to manage cross-tenant data visibility

This commit is contained in:
hamed
2026-08-10 16:22:00 +03:30
parent ee2682e222
commit 2459625c41
8 changed files with 304 additions and 20 deletions
+24
View File
@@ -76,6 +76,30 @@ clinic_uuid صریحِ درخواست > UserActiveContext ذخیره‌شده
| SQL خام DBAL | ❌ |
| فرزندان aggregate | ❌ — همیشه از ریشه JOIN کن |
### استثنای مجاز: دادهٔ «مالِ خودِ کاربر»
چند رکورد در محیطِ یک مطب ثبت می‌شوند ولی مالکشان بیمار است، نه آن مطب: پرداختِ نوبت و
خودِ نوبتِ بیمار. مجوزشان با `user_id` بررسی می‌شود، نه با محیط.
اینجا فیلتر چیزی به امنیت اضافه نمی‌کند و فقط ضرر می‌زند: کاربری که خودش صاحب محیط
دیگری است — پزشکی که از مطب دیگری نوبت می‌گیرد، منشی‌ای که جایی بیمار است — رکورد
خودش را نمی‌دید و صفحهٔ نتیجهٔ پرداخت ۴۰۴ می‌شد.
تنها راه مجاز دورزدن، `App\Shared\Tenant\TenantFilterScope::withoutFilter()` است.
عمداً یک کلاس جداست تا جاهای دورزدن قابل شمردن بمانند، و فیلتر را در `finally`
برمی‌گرداند تا بقیهٔ همان درخواست دوباره محدود شود.
مصرف‌کنندگان فعلی — هر سه کاربرمحور، نه محیط‌محور:
| اندپوینت | چرا |
|---|---|
| `GET /api/v1/payment/{uuid}` | پرداخت‌کننده باید پرداخت خودش را ببیند |
| `GET /api/v1/my/payments` | همان، به شکل فهرست |
| `GET /api/v1/appointments/user` | نوبت‌های خودِ فرد به‌عنوان بیمار |
`PayerSeesOwnPaymentTest` هر سه را می‌بندد و هم‌زمان تأیید می‌کند که پرداختِ کاربر
دیگر همچنان ۴۰۳ می‌گیرد.
**فیلتر جایگزین authorization نیست.** `AppointmentAccessChecker`، `ClinicDoctorAccessChecker`، `SecretaryAccessChecker` و `PatientRecordScopeResolver` سر جایشان می‌مانند: آن‌ها «چه کاری مجاز است» را جواب می‌دهند، فیلتر فقط «کدام ردیف‌ها».
### تغییر رفتار: ۴۰۴ به‌جای ۴۰۳