Enhance user management with SUPER_ADMIN access control

- Updated the user list retrieval logic to ensure proper filtering based on company codes, enhancing security for user data access.
- Implemented checks to restrict access to company management APIs, allowing only SUPER_ADMIN users to perform actions related to company data.
- Adjusted the user interface to reflect access restrictions for non-SUPER_ADMIN users, providing clear feedback when access is denied.

These changes strengthen the integrity of user management and ensure that sensitive company information is only accessible to authorized personnel.
This commit is contained in:
kjs
2026-04-01 15:49:49 +09:00
parent 369a201832
commit 2ff01456dc
11 changed files with 346 additions and 149 deletions

View File

@@ -237,7 +237,7 @@ export const getUserList = async (req: AuthenticatedRequest, res: Response) => {
// 회사 코드 필터 (권한 그룹 멤버 관리 시 사용)
if (companyCode && typeof companyCode === "string" && companyCode.trim()) {
whereConditions.push(`company_code = $${paramIndex}`);
whereConditions.push(`u.company_code = $${paramIndex}`);
queryParams.push(companyCode.trim());
paramIndex++;
logger.info("회사 코드 필터 적용", { companyCode });
@@ -246,7 +246,7 @@ export const getUserList = async (req: AuthenticatedRequest, res: Response) => {
// 최고 관리자 필터링 (회사 관리자와 일반 사용자는 최고 관리자를 볼 수 없음)
if (req.user && req.user.companyCode !== "*") {
// 최고 관리자가 아닌 경우, company_code가 "*"인 사용자는 제외
whereConditions.push(`company_code != '*'`);
whereConditions.push(`u.company_code != '*'`);
logger.info("최고 관리자 필터링 적용", {
userCompanyCode: req.user.companyCode,
});
@@ -259,15 +259,15 @@ export const getUserList = async (req: AuthenticatedRequest, res: Response) => {
const searchTerm = search.trim();
whereConditions.push(`(
sabun ILIKE $${paramIndex} OR
user_type_name ILIKE $${paramIndex} OR
dept_name ILIKE $${paramIndex} OR
position_name ILIKE $${paramIndex} OR
user_id ILIKE $${paramIndex} OR
user_name ILIKE $${paramIndex} OR
tel ILIKE $${paramIndex} OR
cell_phone ILIKE $${paramIndex} OR
email ILIKE $${paramIndex}
u.sabun ILIKE $${paramIndex} OR
u.user_type_name ILIKE $${paramIndex} OR
u.dept_name ILIKE $${paramIndex} OR
u.position_name ILIKE $${paramIndex} OR
u.user_id ILIKE $${paramIndex} OR
u.user_name ILIKE $${paramIndex} OR
u.tel ILIKE $${paramIndex} OR
u.cell_phone ILIKE $${paramIndex} OR
u.email ILIKE $${paramIndex}
)`);
queryParams.push(`%${searchTerm}%`);
paramIndex++;
@@ -277,21 +277,21 @@ export const getUserList = async (req: AuthenticatedRequest, res: Response) => {
// 단일 필드 검색
searchType = "single";
const fieldMap: { [key: string]: string } = {
sabun: "sabun",
companyName: "user_type_name",
deptName: "dept_name",
positionName: "position_name",
userId: "user_id",
userName: "user_name",
tel: "tel",
cellPhone: "cell_phone",
email: "email",
sabun: "u.sabun",
companyName: "u.user_type_name",
deptName: "u.dept_name",
positionName: "u.position_name",
userId: "u.user_id",
userName: "u.user_name",
tel: "u.tel",
cellPhone: "u.cell_phone",
email: "u.email",
};
if (fieldMap[searchField as string]) {
if (searchField === "tel") {
whereConditions.push(
`(tel ILIKE $${paramIndex} OR cell_phone ILIKE $${paramIndex})`
`(u.tel ILIKE $${paramIndex} OR u.cell_phone ILIKE $${paramIndex})`
);
queryParams.push(`%${searchValue}%`);
paramIndex++;
@@ -307,13 +307,13 @@ export const getUserList = async (req: AuthenticatedRequest, res: Response) => {
} else {
// 고급 검색 (개별 필드별 AND 조건)
const advancedSearchFields = [
{ param: search_sabun, field: "sabun" },
{ param: search_companyName, field: "user_type_name" },
{ param: search_deptName, field: "dept_name" },
{ param: search_positionName, field: "position_name" },
{ param: search_userId, field: "user_id" },
{ param: search_userName, field: "user_name" },
{ param: search_email, field: "email" },
{ param: search_sabun, field: "u.sabun" },
{ param: search_companyName, field: "u.user_type_name" },
{ param: search_deptName, field: "u.dept_name" },
{ param: search_positionName, field: "u.position_name" },
{ param: search_userId, field: "u.user_id" },
{ param: search_userName, field: "u.user_name" },
{ param: search_email, field: "u.email" },
];
let hasAdvancedSearch = false;
@@ -330,7 +330,7 @@ export const getUserList = async (req: AuthenticatedRequest, res: Response) => {
// 전화번호 검색
if (search_tel && typeof search_tel === "string" && search_tel.trim()) {
whereConditions.push(
`(tel ILIKE $${paramIndex} OR cell_phone ILIKE $${paramIndex})`
`(u.tel ILIKE $${paramIndex} OR u.cell_phone ILIKE $${paramIndex})`
);
queryParams.push(`%${search_tel.trim()}%`);
paramIndex++;
@@ -354,7 +354,7 @@ export const getUserList = async (req: AuthenticatedRequest, res: Response) => {
// 현재 로그인한 사용자의 회사 코드 필터 (슈퍼관리자가 아닌 경우)
if (req.user && req.user.companyCode !== "*" && !companyCode) {
whereConditions.push(`company_code = $${paramIndex}`);
whereConditions.push(`u.company_code = $${paramIndex}`);
queryParams.push(req.user.companyCode);
paramIndex++;
logger.info("사용자 회사 코드 필터 적용", {
@@ -364,13 +364,13 @@ export const getUserList = async (req: AuthenticatedRequest, res: Response) => {
// 기존 필터들
if (deptCode) {
whereConditions.push(`dept_code = $${paramIndex}`);
whereConditions.push(`u.dept_code = $${paramIndex}`);
queryParams.push(deptCode);
paramIndex++;
}
if (status) {
whereConditions.push(`status = $${paramIndex}`);
whereConditions.push(`u.status = $${paramIndex}`);
queryParams.push(status);
paramIndex++;
}
@@ -383,7 +383,7 @@ export const getUserList = async (req: AuthenticatedRequest, res: Response) => {
// 총 개수 조회
const countQuery = `
SELECT COUNT(*) as total
FROM user_info
FROM user_info u
${whereClause}
`;
const countResult = await query<{ total: string }>(countQuery, queryParams);
@@ -394,26 +394,28 @@ export const getUserList = async (req: AuthenticatedRequest, res: Response) => {
const offset = (Number(page) - 1) * limit;
const usersQuery = `
SELECT
sabun,
user_id,
user_name,
user_name_eng,
dept_code,
dept_name,
position_code,
position_name,
email,
tel,
cell_phone,
user_type,
user_type_name,
regdate,
status,
company_code,
locale
FROM user_info
u.sabun,
u.user_id,
u.user_name,
u.user_name_eng,
u.dept_code,
u.dept_name,
u.position_code,
u.position_name,
u.email,
u.tel,
u.cell_phone,
u.user_type,
u.user_type_name,
u.regdate,
u.status,
u.company_code,
u.locale,
c.company_name
FROM user_info u
LEFT JOIN company_mng c ON u.company_code = c.company_code
${whereClause}
ORDER BY regdate DESC, user_name ASC
ORDER BY u.regdate DESC, u.user_name ASC
LIMIT $${paramIndex} OFFSET $${paramIndex + 1}
`;
@@ -436,6 +438,7 @@ export const getUserList = async (req: AuthenticatedRequest, res: Response) => {
userTypeName: user.user_type_name || null,
status: user.status || "active",
companyCode: user.company_code || null,
companyName: user.company_name || null,
locale: user.locale || null,
regDate: user.regdate
? new Date(user.regdate).toISOString().split("T")[0]