feat: IAM API интеграция + обновление ТЗ + тесты
- src/auth.js: fetchIamUser(), switchProfile(), userFromPayload(iamData) - src/config.js: IAM_API_URL из env - src/routes/oidc.js: обогащение сессии через IAM (с fallback на JWT) - ui/routes/auth.js: обогащение при токен-логине - ui/routes/entries.js: switchTo через POST /switch-profile - src/api/routes/entries.js: resolveCompany через profiles[] - views/index.ejs: переключатель компаний с названиями из profiles - .env.example: IAM_API_URL - docs: обновлены ТЗ-реализация.md, ТЗ-плюс.md, добавлен iam-integration.md - tests: api-crud.sh (14 тестов CRUD + валидации) - .gitignore: исключены .env.test, DEPLOY-TESTING.md
This commit is contained in:
+39
-18
@@ -43,30 +43,51 @@ function createRouter({ auth, doubleCsrfProtection, generateCsrfToken, authLimit
|
||||
}
|
||||
|
||||
try {
|
||||
// Обмен code на токен (через Keycloak или API Gateway)
|
||||
// Обмен code на токен (через IAM / Keycloak)
|
||||
const tokenData = await auth.exchangeCode(code);
|
||||
const accessToken = tokenData.access_token;
|
||||
const accessToken = tokenData.accessToken;
|
||||
|
||||
// Верификация токена (проверка подписи через JWKS)
|
||||
// userFromPayload уже встроена в exchangeCode или делается здесь
|
||||
if (!accessToken) throw new Error('No access_token in response');
|
||||
|
||||
// Базовый user из JWT (fallback)
|
||||
const payload = jwt.decode(accessToken);
|
||||
if (!payload) throw new Error('Failed to decode token');
|
||||
|
||||
// Определяем компании пользователя
|
||||
const rawClientId = payload.ClientID || payload.client_id || '';
|
||||
const allClientIds = rawClientId.split(',').map(s => s.trim()).filter(Boolean);
|
||||
const activeClientId = allClientIds[0] || rawClientId;
|
||||
|
||||
req.session.token = accessToken;
|
||||
req.session.user = {
|
||||
clientId: rawClientId,
|
||||
allClientIds,
|
||||
activeClientId,
|
||||
email: payload.email || payload.login || '',
|
||||
companyId: payload.company_id || payload.companyId || null,
|
||||
companyName: payload.company_name || payload.companyName || activeClientId,
|
||||
isAdmin: activeClientId === (process.env.ADMIN_CLIENT_ID || 'WZ01112'),
|
||||
};
|
||||
|
||||
// Пытаемся обогатить через IAM API
|
||||
try {
|
||||
const { fetchIamUser } = require('../auth');
|
||||
const iamData = await fetchIamUser(accessToken);
|
||||
req.session.user = {
|
||||
email: iamData.email,
|
||||
clientId: iamData.clientId,
|
||||
allClientIds: iamData.allClientIds,
|
||||
activeClientId: iamData.clientId,
|
||||
activeProfileId: iamData.activeProfileId,
|
||||
companyId: iamData.companyId,
|
||||
companyName: iamData.companyName,
|
||||
isAdmin: iamData.isAdmin,
|
||||
fio: iamData.fio,
|
||||
profiles: iamData.profiles,
|
||||
};
|
||||
console.log('[oidc] IAM enrichment OK:', iamData.email, iamData.clientId, 'profiles:', iamData.allClientIds.length);
|
||||
} catch (iamErr) {
|
||||
// IAM недоступен — используем fallback из JWT
|
||||
console.warn('[oidc] IAM enrichment failed, using JWT fallback:', iamErr.message);
|
||||
const rawClientId = payload.ClientID || payload.client_id || '';
|
||||
const allClientIds = rawClientId.split(',').map(s => s.trim()).filter(Boolean);
|
||||
const activeClientId = allClientIds[0] || rawClientId || 'UNKNOWN';
|
||||
req.session.user = {
|
||||
clientId: activeClientId,
|
||||
allClientIds,
|
||||
activeClientId,
|
||||
email: payload.email || payload.login || '',
|
||||
companyId: payload.company_id || null,
|
||||
companyName: payload.company_name || activeClientId,
|
||||
isAdmin: activeClientId === (process.env.ADMIN_CLIENT_ID || 'WZ01112'),
|
||||
};
|
||||
}
|
||||
|
||||
const returnTo = req.session.oidcReturnTo || '/';
|
||||
delete req.session.oidcReturnTo;
|
||||
|
||||
Reference in New Issue
Block a user