feat: Complete Phase 1.5 - AuthService Raw Query migration
Phase 1.5 완료: 인증 서비스 Raw Query 전환 및 테스트 완료 ✅ AuthService 전환 완료 (5개 Prisma 호출 제거): - loginPwdCheck(): Raw Query로 사용자 비밀번호 조회 - insertLoginAccessLog(): Raw Query로 로그인 로그 기록 - getUserInfo(): Raw Query로 사용자/권한/회사 정보 조회 - authority_sub_user ↔ authority_master JOIN (master_objid ↔ objid) - 3개 쿼리로 분리 (사용자, 권한, 회사) - processLogin(): 전체 로그인 플로우 통합 - processLogout(): 로그아웃 로그 기록 🧪 테스트 완료: - 단위 테스트: 30개 테스트 모두 통과 ✅ - 로그인 검증 (6개) - 사용자 정보 조회 (5개) - 로그인 로그 기록 (4개) - 전체 로그인 프로세스 (5개) - 로그아웃 (2개) - 토큰 검증 (3개) - Raw Query 전환 검증 (3개) - 성능 테스트 (2개) - 통합 테스트: 작성 완료 (auth.integration.test.ts) - 로그인 → 토큰 발급 → 인증 → 로그아웃 플로우 🔧 주요 변경사항: - Prisma import 제거 → Raw Query (query from db.ts) - authority 테이블 JOIN 수정 (auth_code → master_objid/objid) - 파라미터 바인딩으로 SQL Injection 방지 - 타입 안전성 유지 (TypeScript Generic 사용) 📊 성능: - 로그인 프로세스: < 1초 - 사용자 정보 조회: < 500ms - 모든 테스트 실행 시간: 2.016초 🎯 다음 단계: - Phase 2: 핵심 서비스 전환 (ScreenManagement, TableManagement 등) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -1,7 +1,8 @@
|
||||
// 인증 서비스
|
||||
// 기존 Java LoginService를 Node.js로 포팅
|
||||
// ✅ Prisma → Raw Query 전환 완료 (Phase 1.5)
|
||||
|
||||
import prisma from "../config/database";
|
||||
import { query } from "../database/db";
|
||||
import { JwtUtils } from "../utils/jwtUtils";
|
||||
import { EncryptUtil } from "../utils/encryptUtil";
|
||||
import { PersonBean, LoginResult, LoginLogData } from "../types/auth";
|
||||
@@ -17,15 +18,13 @@ export class AuthService {
|
||||
password: string
|
||||
): Promise<LoginResult> {
|
||||
try {
|
||||
// 사용자 비밀번호 조회 (기존 login.getUserPassword 쿼리 포팅)
|
||||
const userInfo = await prisma.user_info.findUnique({
|
||||
where: {
|
||||
user_id: userId,
|
||||
},
|
||||
select: {
|
||||
user_password: true,
|
||||
},
|
||||
});
|
||||
// 사용자 비밀번호 조회 (Raw Query 전환)
|
||||
const result = await query<{ user_password: string }>(
|
||||
"SELECT user_password FROM user_info WHERE user_id = $1",
|
||||
[userId]
|
||||
);
|
||||
|
||||
const userInfo = result.length > 0 ? result[0] : null;
|
||||
|
||||
if (userInfo && userInfo.user_password) {
|
||||
const dbPassword = userInfo.user_password;
|
||||
@@ -78,32 +77,26 @@ export class AuthService {
|
||||
*/
|
||||
static async insertLoginAccessLog(logData: LoginLogData): Promise<void> {
|
||||
try {
|
||||
// 기존 login.insertLoginAccessLog 쿼리 포팅
|
||||
await prisma.$executeRaw`
|
||||
INSERT INTO LOGIN_ACCESS_LOG(
|
||||
LOG_TIME,
|
||||
SYSTEM_NAME,
|
||||
USER_ID,
|
||||
LOGIN_RESULT,
|
||||
ERROR_MESSAGE,
|
||||
REMOTE_ADDR,
|
||||
RECPTN_DT,
|
||||
RECPTN_RSLT_DTL,
|
||||
RECPTN_RSLT,
|
||||
RECPTN_RSLT_CD
|
||||
// 로그인 로그 기록 (Raw Query 전환)
|
||||
await query(
|
||||
`INSERT INTO LOGIN_ACCESS_LOG(
|
||||
LOG_TIME, SYSTEM_NAME, USER_ID, LOGIN_RESULT, ERROR_MESSAGE,
|
||||
REMOTE_ADDR, RECPTN_DT, RECPTN_RSLT_DTL, RECPTN_RSLT, RECPTN_RSLT_CD
|
||||
) VALUES (
|
||||
now(),
|
||||
${logData.systemName},
|
||||
UPPER(${logData.userId}),
|
||||
${logData.loginResult},
|
||||
${logData.errorMessage || null},
|
||||
${logData.remoteAddr},
|
||||
${logData.recptnDt || null},
|
||||
${logData.recptnRsltDtl || null},
|
||||
${logData.recptnRslt || null},
|
||||
${logData.recptnRsltCd || null}
|
||||
)
|
||||
`;
|
||||
now(), $1, UPPER($2), $3, $4, $5, $6, $7, $8, $9
|
||||
)`,
|
||||
[
|
||||
logData.systemName,
|
||||
logData.userId,
|
||||
logData.loginResult,
|
||||
logData.errorMessage || null,
|
||||
logData.remoteAddr,
|
||||
logData.recptnDt || null,
|
||||
logData.recptnRsltDtl || null,
|
||||
logData.recptnRslt || null,
|
||||
logData.recptnRsltCd || null,
|
||||
]
|
||||
);
|
||||
|
||||
logger.info(
|
||||
`로그인 로그 기록 완료: ${logData.userId} (${logData.loginResult ? "성공" : "실패"})`
|
||||
@@ -122,66 +115,61 @@ export class AuthService {
|
||||
*/
|
||||
static async getUserInfo(userId: string): Promise<PersonBean | null> {
|
||||
try {
|
||||
// 기존 login.getUserInfo 쿼리 포팅
|
||||
const userInfo = await prisma.user_info.findUnique({
|
||||
where: {
|
||||
user_id: userId,
|
||||
},
|
||||
select: {
|
||||
sabun: true,
|
||||
user_id: true,
|
||||
user_name: true,
|
||||
user_name_eng: true,
|
||||
user_name_cn: true,
|
||||
dept_code: true,
|
||||
dept_name: true,
|
||||
position_code: true,
|
||||
position_name: true,
|
||||
email: true,
|
||||
tel: true,
|
||||
cell_phone: true,
|
||||
user_type: true,
|
||||
user_type_name: true,
|
||||
partner_objid: true,
|
||||
company_code: true,
|
||||
locale: true,
|
||||
photo: true,
|
||||
},
|
||||
});
|
||||
// 1. 사용자 기본 정보 조회 (Raw Query 전환)
|
||||
const userResult = await query<{
|
||||
sabun: string | null;
|
||||
user_id: string;
|
||||
user_name: string;
|
||||
user_name_eng: string | null;
|
||||
user_name_cn: string | null;
|
||||
dept_code: string | null;
|
||||
dept_name: string | null;
|
||||
position_code: string | null;
|
||||
position_name: string | null;
|
||||
email: string | null;
|
||||
tel: string | null;
|
||||
cell_phone: string | null;
|
||||
user_type: string | null;
|
||||
user_type_name: string | null;
|
||||
partner_objid: string | null;
|
||||
company_code: string | null;
|
||||
locale: string | null;
|
||||
photo: Buffer | null;
|
||||
}>(
|
||||
`SELECT
|
||||
sabun, user_id, user_name, user_name_eng, user_name_cn,
|
||||
dept_code, dept_name, position_code, position_name,
|
||||
email, tel, cell_phone, user_type, user_type_name,
|
||||
partner_objid, company_code, locale, photo
|
||||
FROM user_info
|
||||
WHERE user_id = $1`,
|
||||
[userId]
|
||||
);
|
||||
|
||||
const userInfo = userResult.length > 0 ? userResult[0] : null;
|
||||
|
||||
if (!userInfo) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// 권한 정보 조회 (Prisma ORM 사용)
|
||||
const authInfo = await prisma.authority_sub_user.findMany({
|
||||
where: {
|
||||
user_id: userId,
|
||||
},
|
||||
include: {
|
||||
authority_master: {
|
||||
select: {
|
||||
auth_name: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
// 2. 권한 정보 조회 (Raw Query 전환 - JOIN으로 최적화)
|
||||
const authResult = await query<{ auth_name: string }>(
|
||||
`SELECT am.auth_name
|
||||
FROM authority_sub_user asu
|
||||
INNER JOIN authority_master am ON asu.master_objid = am.objid
|
||||
WHERE asu.user_id = $1`,
|
||||
[userId]
|
||||
);
|
||||
|
||||
// 권한명들을 쉼표로 연결
|
||||
const authNames = authInfo
|
||||
.filter((auth: any) => auth.authority_master?.auth_name)
|
||||
.map((auth: any) => auth.authority_master!.auth_name!)
|
||||
.join(",");
|
||||
const authNames = authResult.map((row) => row.auth_name).join(",");
|
||||
|
||||
// 회사 정보 조회 (Prisma ORM 사용으로 변경)
|
||||
const companyInfo = await prisma.company_mng.findFirst({
|
||||
where: {
|
||||
company_code: userInfo.company_code || "ILSHIN",
|
||||
},
|
||||
select: {
|
||||
company_name: true,
|
||||
},
|
||||
});
|
||||
// 3. 회사 정보 조회 (Raw Query 전환)
|
||||
// Note: 현재 회사 정보는 PersonBean에 직접 사용되지 않지만 향후 확장을 위해 유지
|
||||
const companyResult = await query<{ company_name: string }>(
|
||||
"SELECT company_name FROM company_mng WHERE company_code = $1",
|
||||
[userInfo.company_code || "ILSHIN"]
|
||||
);
|
||||
|
||||
// DB에서 조회한 원본 사용자 정보 상세 로그
|
||||
//console.log("🔍 AuthService - DB 원본 사용자 정보:", {
|
||||
|
||||
Reference in New Issue
Block a user