quality / commitlint (push) Skipped
quality / changes (push) Successful in 7s
quality / docker-check (push) Skipped
quality / web (push) Successful in 40s
quality / api (push) Successful in 36s
CD / quality (push) Successful in 1m37s
CD / publish (push) Successful in 1m40s
Регистрация mm в каталоге приложений, permissions mm:*, target-app и docs. Co-authored-by: Cursor <[email protected]>
113 lines
3.8 KiB
Markdown
113 lines
3.8 KiB
Markdown
# Интеграция auth-portal ↔ MikrotikManager
|
||
|
||
Единый вход: пользователь логинится на auth-portal, получает JWT, переходит в MikrotikManager с токеном в URL fragment. Backend MM проверяет JWT и права `mm:*`.
|
||
|
||
## Архитектура
|
||
|
||
```
|
||
Browser → MikrotikManager UI (нет token)
|
||
→ redirect AUTH_PORTAL_URL/?return_to=…/auth/callback
|
||
→ login
|
||
→ redirect return_to#access_token=…
|
||
→ MM /auth/callback сохраняет token (mmapp_token)
|
||
→ API Authorization: Bearer …
|
||
```
|
||
|
||
Общий секрет: `JWT_SECRET` / `AUTH_JWT_SECRET` (HS256). Issuer: `ISSUER` / `AUTH_ISSUER`.
|
||
|
||
App id в портале: **`mm`** (каталог permissions).
|
||
|
||
## Локальный запуск
|
||
|
||
### 1. auth-portal
|
||
|
||
```bash
|
||
cd auth-portal
|
||
pnpm install
|
||
# JWT_SECRET=dev-secret-change-me
|
||
# RETURN_TO_ALLOWLIST=.shnt.top,localhost,http://localhost:3000
|
||
pnpm --filter @authportal/api dev # :8080
|
||
pnpm --filter web dev # :5175
|
||
```
|
||
|
||
Bootstrap: `[email protected]` / `admin`. В админке выдайте app **mm** и permissions `mm:*`.
|
||
|
||
### 2. MikrotikManager
|
||
|
||
```bash
|
||
cd MikrotikManager
|
||
npm install
|
||
```
|
||
|
||
Backend `backend/.env`:
|
||
|
||
```env
|
||
AUTH_REQUIRED=true
|
||
AUTH_JWT_SECRET=dev-secret-change-me
|
||
AUTH_ISSUER=https://auth.shnt.top
|
||
AUTH_PORTAL_URL=http://localhost:5175
|
||
CORS_ORIGIN=http://localhost:3000
|
||
```
|
||
|
||
Frontend: `NEXT_PUBLIC_AUTH_PORTAL_URL=http://localhost:5175` (или runtime `GET /api/auth/config` через proxy).
|
||
|
||
```bash
|
||
npm --prefix backend run dev
|
||
npm run dev
|
||
```
|
||
|
||
Откройте `http://localhost:3000` → редирект на portal → после логина NavUser показывает имя/email.
|
||
|
||
## Permissions ↔ API / UI
|
||
|
||
Иерархия: `admin` ⊃ `write` ⊃ `read` в рамках одной секции.
|
||
|
||
| Permission | API (prefix) | UI |
|
||
|------------|--------------|-----|
|
||
| `mm:dashboard:read` | sidebar-counts, events (GET) | `/dashboard` |
|
||
| `mm:servers:read` / `write` | `/api/servers*` | `/servers` |
|
||
| `mm:filters:read` / `write` | `/api/filters*` | `/filters`, GRE |
|
||
| `mm:bgp:read` / `write` | `/api/bgp*` | BGP |
|
||
| `mm:uptime:read` / `write` | `/api/uptime*` | `/uptime` |
|
||
| `mm:traffic:read` / `write` | `/api/traffic*` | `/traffic` |
|
||
| `mm:alerts:read` / `write` | `/api/alerts*` | `/alerts` |
|
||
| `mm:backups:read` / `write` | `/api/backups*` | `/backups` |
|
||
| `mm:certificates:read` / `write` | `/api/certificates*` | certificates |
|
||
| `mm:network:read` / `write` | `/api/network*`, OSPF, recursive, probes | network |
|
||
| `mm:settings:admin` | `/api/system/*`, scheduler, evobgp settings | `/settings` |
|
||
|
||
Без app `mm` в JWT `apps` → **403** на защищённые `/api/*`.
|
||
|
||
`AUTH_REQUIRED=false` — API открыт (dev без portal).
|
||
|
||
## App Switcher
|
||
|
||
`CURRENT_APP_ID = mm`. Публичный конфиг: `GET {AUTH_PORTAL_URL}/api/v1/app-switcher`.
|
||
|
||
## Logout (SSO)
|
||
|
||
Очистить `mmapp_token` → редирект на **`{AUTH_PORTAL_URL}/logout`**.
|
||
|
||
## Production
|
||
|
||
См. общий стек CDN+MM: `deploy/docker-compose.cdn-mm.yml` / `deploy/env.cdn-mm.example`.
|
||
|
||
```env
|
||
AUTH_REQUIRED=true
|
||
AUTH_JWT_SECRET=<тот же JWT_SECRET портала>
|
||
AUTH_ISSUER=https://auth.shnt.top
|
||
AUTH_PORTAL_URL=https://auth.shnt.top
|
||
CORS_ORIGIN=https://mm.shnt.top
|
||
```
|
||
|
||
В portal: `RETURN_TO_ALLOWLIST` включает `https://mm.shnt.top` (или `.shnt.top`).
|
||
|
||
## Troubleshooting
|
||
|
||
| Симптом | Причина |
|
||
|---------|---------|
|
||
| SSO loop | разный `JWT_SECRET` или `ISSUER` |
|
||
| 403 «Нет доступа к приложению» | нет app `mm` у пользователя |
|
||
| 403 «Недостаточно прав» | нет нужного `mm:…` |
|
||
| return_to rejected | origin MM не в `RETURN_TO_ALLOWLIST` |
|