v0.5.123: switchTo перед crud.list, activeClientId не затирается

This commit is contained in:
2026-06-15 16:16:36 +04:00
parent f215fa8e32
commit e2aaf3f425
5 changed files with 86 additions and 18 deletions
+76
View File
@@ -0,0 +1,76 @@
# Баг: переключение компании — таблица IP не обновляется
## Симптом
GET /v2/app?switchTo=WZ30001 → таблица показывает записи старой компании.
## Найденная причина №1 (основная)
Порядок кода в `v2/src/user/index.js`:
```js
// 1. clId = req.clientId ← resolveContext выставил СТАРЫЙ activeClientId
const clId = req.clientId;
// 2. crud.list() по СТАРОМУ clId — ещё до switchTo
const { entries, used, limit } = await crud.list(clId, includeDeleted);
// 3. Потом switchTo обновляет сессию и делает redirect
if (req.query.switchTo) {
req.session.user.activeClientId = targetId;
return req.session.save(() => res.redirect('/v2/app'));
}
```
Итог: первый запрос с ?switchTo загружает записи СТАРОЙ компании.
Второй запрос (редирект /v2/app) должен уже использовать новый activeClientId — если ничто его не затирает.
## Найденная причина №2 (если ENV заданы)
`v2/src/impersonation/index.js` — при тестовом режиме (IMPERSONATION_TARGET задан):
```js
u.activeClientId = MAIN_COMPANY; // ← затирает то что записал switchTo
```
Middleware запускается при КАЖДОМ запросе (включая редирект после switchTo)
и сбрасывает activeClientId обратно в IMPERSONATION_COMPANY.
## Что проверить
```bash
echo $IMPERSONATION_COMPANY
echo $IMPERSONATION_TARGET
echo $IMPERSONATION_ORIGINAL
```
Если заданы → причина №2 (middleware затирает сессию).
Если не заданы → причина №1 (но тогда второй запрос после редиректа должен работать).
## Фикс причины №1
В `v2/src/user/index.js` — переставить проверку switchTo ПЕРЕД crud.list():
```js
// Сначала switchTo
if (req.query.switchTo) {
const targetId = req.query.switchTo;
const allowed = isAdmin || (req.profiles || []).find(p => p.client_id === targetId);
if (allowed) {
req.session.user.activeClientId = targetId;
return req.session.save(err => {
if (err) console.error('[switchTo] save error:', err.message);
res.redirect('/v2/app');
});
}
}
// Потом загружать записи
const { entries, used, limit } = await crud.list(clId, includeDeleted);
```
## Фикс причины №2
В `v2/src/impersonation/index.js` — не перезаписывать activeClientId если он уже есть:
```js
// Вместо:
u.activeClientId = MAIN_COMPANY;
// Сделать:
u.activeClientId = u.activeClientId || MAIN_COMPANY;
```
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "ipwhitelist", "name": "ipwhitelist",
"version": "0.5.122", "version": "0.5.123",
"description": "IP WhiteList microservice for cloud provider", "description": "IP WhiteList microservice for cloud provider",
"main": "server.js", "main": "server.js",
"scripts": { "scripts": {
+1 -1
View File
@@ -9,7 +9,7 @@
// ═══════════════════════════════════════════════════════════════════════════════ // ═══════════════════════════════════════════════════════════════════════════════
module.exports = { module.exports = {
version: '0.5.122', version: '0.5.123',
// ── IAM ────────────────────────────────────────────────────────────────── // ── IAM ──────────────────────────────────────────────────────────────────
iamUrl: process.env.V2_IAM_URL || 'https://auth-api.ngcloud.ru/api/v1/auth/user', iamUrl: process.env.V2_IAM_URL || 'https://auth-api.ngcloud.ru/api/v1/auth/user',
+1 -1
View File
@@ -40,7 +40,7 @@ function enhanceImpersonation(req, res, next) {
// Подменяем ВСЕ данные на таргета (как делает IAM) // Подменяем ВСЕ данные на таргета (как делает IAM)
u.email = TARGET_EMAIL; u.email = TARGET_EMAIL;
u.clientId = MAIN_COMPANY; u.clientId = MAIN_COMPANY;
u.activeClientId = MAIN_COMPANY; u.activeClientId = u.activeClientId || MAIN_COMPANY;
u.allClientIds = ALL_TARGET_CIDS; u.allClientIds = ALL_TARGET_CIDS;
u.companyName = MAIN_COMPANY; u.companyName = MAIN_COMPANY;
u.isAdmin = wasAdmin; u.isAdmin = wasAdmin;
+6 -14
View File
@@ -49,21 +49,10 @@ function createUserRouter() {
: [{ client_id: clId, name: req.companyName || clId, is_active: true }]; : [{ client_id: clId, name: req.companyName || clId, is_active: true }];
} }
// ── Записи ────────────────────────────────────────────────────── // ── Переключение компании (до crud.list — не грузить зря) ────
const includeDeleted = req.query.deleted === '1';
const { entries, used, limit } = await crud.list(clId, includeDeleted);
// ── Переключение компании ──────────────────────────────────────
if (req.query.switchTo) { if (req.query.switchTo) {
const targetId = req.query.switchTo; const targetId = req.query.switchTo;
if (isAdmin) { const allowed = isAdmin || (req.profiles || []).find(p => p.client_id === targetId);
req.session.user.activeClientId = targetId;
return req.session.save(err => {
if (err) console.error('[switchTo] save error:', err.message);
res.redirect('/v2/app');
});
} else {
const allowed = (req.profiles || []).find(p => p.client_id === targetId);
if (allowed) { if (allowed) {
req.session.user.activeClientId = targetId; req.session.user.activeClientId = targetId;
return req.session.save(err => { return req.session.save(err => {
@@ -72,7 +61,10 @@ function createUserRouter() {
}); });
} }
} }
}
// ── Записи ──────────────────────────────────────────────────────
const includeDeleted = req.query.deleted === '1';
const { entries, used, limit } = await crud.list(clId, includeDeleted);
// ── Данные пользователя для шаблона ──────────────────────────── // ── Данные пользователя для шаблона ────────────────────────────
const sessionUser = req.session && req.session.user ? req.session.user : {}; const sessionUser = req.session && req.session.user ? req.session.user : {};