82 lines
5.5 KiB
Plaintext
82 lines
5.5 KiB
Plaintext
---
|
|
description: اتصال ورود ادمین به سامانه هویت متمرکز (IAM) — مرزها و قواعدی که نباید شکسته شوند
|
|
globs:
|
|
alwaysApply: true
|
|
---
|
|
|
|
# اتصال به سامانه هویت متمرکز (Central IAM)
|
|
|
|
مستندها:
|
|
- `docs/iam-connection.md` — **نحوه ارتباط**: سه کانال داده و رفتار در خطا
|
|
- `docs/iam-sso.md` — پیکربندی، ابطال نشست، محدودیتها
|
|
- مرجع تصویری اندپوینتهای IAM: `<IAM>/docs` (Scalar)
|
|
|
|
## اصل غیرقابلمذاکره
|
|
|
|
این قابلیت **افزایشی** است. با `IAM_ENABLED=false` (پیشفرض) سامانه باید دقیقاً
|
|
مثل قبل رفتار کند: یک `bcrypt.compare` محلی و هیچ درخواست شبکهای.
|
|
|
|
- **هیچ تغییری در رابط کاربری نیست.** نه دکمه SSO، نه ریدایرکت، نه صفحه جدید.
|
|
ادمین مثل همیشه موبایل و رمز را در همین پنل وارد میکند.
|
|
- پاسخ `POST /api/admin/auth/login` در هر دو حالت یکسان است (`api_token`,
|
|
`roles`, …) پس پنل ادمین تفاوتی نمیبیند.
|
|
|
|
## نقشه فایلها
|
|
|
|
| مسیر | نقش |
|
|
| --- | --- |
|
|
| `apps/api/src/modules/iam/iam.service.ts` | ارتباط با IAM و نگاشت خطاها |
|
|
| `apps/api/src/modules/iam/iam.module.ts` | ماژول Global (بیاثر تا زمان روشن شدن) |
|
|
| `apps/api/src/modules/auth/auth.service.ts` | متد `verifyPassword` — تنها نقطه اتصال ورود |
|
|
| `apps/api/src/modules/sessions/admin-session.service.ts` | نشستهای قابل ابطال (`jti`) |
|
|
| `apps/api/src/modules/iam/iam-logout.service.ts` | تأیید توکن خروج سراسری (JWKS، RS256) |
|
|
| `apps/api/src/modules/iam/iam.controller.ts` | `POST /api/iam/backchannel-logout` |
|
|
|
|
## قواعد سخت
|
|
|
|
1. **هر نتیجه مبهم باید به `bcrypt` محلی برگردد.** سرویس در دسترس نیست، کاربر
|
|
آنجا نیست، یا ۴۲۹ گرفتیم ⇒ رمز محلی بررسی شود. فقط `exclusive` اجازه رد
|
|
کردن دارد. خرابی IAM هرگز نباید ادمینها را بیرون بیندازد.
|
|
|
|
2. **حساب قفلشده، «نتیجه قطعی» است نه خطا.** `account_locked` نباید به
|
|
`bcrypt` محلی برگردد وگرنه قفلِ IAM بیاثر میشود.
|
|
|
|
3. **`client_ip` همیشه فرستاده میشود.** بدون آن، محدودیت نرخِ IAM روی IP همین
|
|
سرور اعمال میشود و بعد از چند ورود کل پنل ادمین ۴۲۹ میگیرد. اگر API پشت
|
|
پراکسی رفت، `trust proxy` را تنظیم کن وگرنه `@Ip()` همیشه IP پراکسی است.
|
|
|
|
4. **هیچ جدول موجودی تغییر نمیکند.** نگاشت کاربر با همان `mobile` انجام میشود و
|
|
`iamSub`/`iamSessionId` روی جدول **جدید** `AdminSession` مینشینند، نه روی
|
|
`AdminUser`. اگر روزی چیزی از IAM لازم شد، همین الگو را نگه دار.
|
|
|
|
5. **ابطال نشست دو شرط دارد و هر دو لازم است:** توکن باید `jti` داشته باشد و ردیف
|
|
`AdminSession` باید موجود و باطلنشده باشد. با خاموش بودن ردیابی
|
|
(`AUTH_SESSION_TRACKING=false` یا IAM خاموش) نه `jti` صادر میشود، نه کوئری
|
|
اضافهای در مسیر احراز هویت اجرا میشود — یعنی دقیقاً رفتار و هزینه قبلی.
|
|
توکن بدون `jti` هرگز نباید رد شود، وگرنه روشن کردن این کلید همه را بیرون میاندازد.
|
|
|
|
6. **اندپوینت خروج سراسری بدون احراز هویت است و باید بماند.** اعتبارش از امضای
|
|
`logout_token` میآید: `iss`، `aud`، `events`، نبودن `nonce` و `exp` همه بررسی
|
|
میشوند. هیچیک از این بررسیها را برای «راحتی تست» حذف نکن. پاسخ همیشه ۲۰۰ است
|
|
تا IdP بینهایت تلاش مجدد نکند؛ دلیل رد شدن فقط لاگ میشود.
|
|
|
|
7. **فرم ورود این پنل مرحله «ورود کد» ندارد**، پس حساب دو مرحلهای در IAM از این
|
|
مسیر قابل تکمیل نیست و با پیام روشن رد میشود. تا وقتی آن مرحله ساخته نشده،
|
|
تلاش برای تکمیل 2FA در بکاند بیمعناست.
|
|
|
|
8. **ورود اپ کاربر رمز ندارد**، پس از `verifyCredentials` استفاده نمیشود؛ بعد از
|
|
بررسی موفق کد، `IamService.attestOtpLogin` فراخوانی میشود. قاعده خطا: «کاربر
|
|
آنجا نیست» و «سرویس در دسترس نیست» ⇒ ورود ادامه مییابد؛ «قفل/غیرفعال/دو
|
|
مرحلهای» ⇒ ورود رد میشود. کد اضطراری تحویل (`OTP_MASTER_CODE`) هرگز به IAM
|
|
اعلام نمیشود.
|
|
|
|
9. پیکربندی ناقص = خاموش. `IamService.enabled` وجود `issuer`, `client_id` و
|
|
`client_secret` را هم شرط میکند (با `envOr` که مقدار خالی را unset میشمارد).
|
|
|
|
## قبل از تحویل
|
|
|
|
```bash
|
|
cd apps/api && npx jest src/modules/iam src/modules/auth src/modules/sessions
|
|
# و در استقرار: prisma migrate deploy (جدول AdminSession)
|
|
```
|