feat: Implement user ID duplication check in user registration and update processes

- Added functionality to check for existing user IDs during new user registration and updates to prevent overwriting accounts from different companies.
- Enhanced error handling to return appropriate messages when a duplicate user ID is detected.
- Updated the frontend to include user ID duplication verification, ensuring a smoother user experience during user creation and editing.
- These changes aim to improve data integrity and user management across multiple company implementations.
This commit is contained in:
kjs
2026-04-13 18:20:24 +09:00
parent 21b4459757
commit 2c75677394
32 changed files with 1104 additions and 217 deletions

View File

@@ -949,14 +949,25 @@ export async function addTableData(
const tableManagementService = new TableManagementService();
// 🆕 멀티테넌시: company_code 자동 추가 (테이블에 company_code 컬럼이 있는 경우)
// 🆕 멀티테넌시: company_code 강제 설정 (테이블에 company_code 컬럼이 있는 경우)
// 일반 관리자는 자신의 company_code로 강제, 슈퍼관리자(*)는 클라이언트 값 허용(프리뷰용)
const companyCode = req.user?.companyCode;
if (companyCode && !data.company_code) {
// 테이블에 company_code 컬럼이 있는지 확인
if (companyCode) {
const hasCompanyCodeColumn = await tableManagementService.hasColumn(tableName, "company_code");
if (hasCompanyCodeColumn) {
data.company_code = companyCode;
logger.info(`멀티테넌시: company_code 자동 추가 - ${companyCode}`);
if (companyCode === "*") {
// 슈퍼관리자: 클라이언트가 보낸 company_code 허용, 없으면 '*'
if (!data.company_code) {
data.company_code = companyCode;
logger.info(`멀티테넌시: company_code 자동 추가 - ${companyCode}`);
}
} else {
// 일반 관리자: 항상 자신의 company_code로 강제 (타 회사 주입 방지)
if (data.company_code && data.company_code !== companyCode) {
logger.warn(`멀티테넌시: 타 회사 company_code 주입 시도 차단 - 요청값: ${data.company_code}, 강제값: ${companyCode}`);
}
data.company_code = companyCode;
}
}
}
@@ -1115,6 +1126,37 @@ export async function editTableData(
const tableManagementService = new TableManagementService();
const companyCode = req.user?.companyCode || "*";
// 🔒 멀티테넌시 보안: 일반 관리자는 타 회사 데이터 수정 불가 + company_code 변경 차단
if (companyCode !== "*") {
const hasCompanyCodeColumn = await tableManagementService.hasColumn(tableName, "company_code");
if (hasCompanyCodeColumn) {
// 1. 원본 데이터의 company_code 확인
if (originalData?.id) {
try {
const existing = await tableManagementService.getTableData(tableName, {
page: 1, size: 1,
search: { id: String(originalData.id) },
});
const existingRow = existing.data?.[0];
if (existingRow && existingRow.company_code && existingRow.company_code !== companyCode && existingRow.company_code !== "*") {
logger.warn(`🔒 타 회사 데이터 수정 차단: ${tableName} id=${originalData.id}, 요청자=${companyCode}, 데이터소속=${existingRow.company_code}`);
res.status(403).json({
success: false,
message: "해당 데이터를 수정할 권한이 없습니다.",
error: { code: "FORBIDDEN_COMPANY", details: "cross-company edit blocked" },
});
return;
}
} catch { /* skip 검증 실패 시 원래 흐름 진행 */ }
}
// 2. updatedData에 company_code 변경 시도가 있으면 제거
if (updatedData.company_code && updatedData.company_code !== companyCode) {
logger.warn(`🔒 company_code 변경 시도 차단: ${tableName}, 요청값=${updatedData.company_code}`);
delete updatedData.company_code;
}
}
}
// 회사별 NOT NULL 소프트 제약조건 검증 (수정 데이터 대상)
const notNullViolations = await tableManagementService.validateNotNullConstraints(
tableName,