diff --git a/WebContent/jsp/common/screen/main.jsp b/WebContent/jsp/common/screen/main.jsp index 5c2fbb8..0642401 100644 --- a/WebContent/jsp/common/screen/main.jsp +++ b/WebContent/jsp/common/screen/main.jsp @@ -5,6 +5,7 @@ <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%> <%@ taglib uri="http://www.springframework.org/tags" prefix="spring"%> <%@ include file="/jsp/common/include/localemessage.jsp" %> +" scope="session" /> <% String topPage = request.getContextPath() + StringUtils.defaultString((String) request.getAttribute("topPage"), "/top_04.do"); diff --git a/src/main/java/com/eactive/eai/rms/data/entity/onl/apim/portalorg/PortalOrgRepository.java b/src/main/java/com/eactive/eai/rms/data/entity/onl/apim/portalorg/PortalOrgRepository.java index ac06aed..92a9de5 100644 --- a/src/main/java/com/eactive/eai/rms/data/entity/onl/apim/portalorg/PortalOrgRepository.java +++ b/src/main/java/com/eactive/eai/rms/data/entity/onl/apim/portalorg/PortalOrgRepository.java @@ -4,7 +4,15 @@ import com.eactive.apim.portal.portalorg.entity.PortalOrg; import com.eactive.eai.data.jpa.BaseRepository; import com.eactive.eai.rms.data.EMSDataSource; +import java.util.Optional; + @EMSDataSource public interface PortalOrgRepository extends BaseRepository { + /** + * 기관코드로 기관 조회 + * @param orgCode 기관코드 (OBP 파트너코드) + * @return 기관 정보 + */ + Optional findByOrgCode(String orgCode); } diff --git a/src/main/java/com/eactive/eai/rms/ext/kjb/sso/SsoController.java b/src/main/java/com/eactive/eai/rms/ext/kjb/sso/SsoController.java index fc80538..63572ce 100644 --- a/src/main/java/com/eactive/eai/rms/ext/kjb/sso/SsoController.java +++ b/src/main/java/com/eactive/eai/rms/ext/kjb/sso/SsoController.java @@ -106,39 +106,49 @@ public class SsoController implements InterceptorSkipController { return "redirect:/loginForm.do"; } - // 기본 정보 - Properties info = ssoModule.getUserInfos(ssoId); - // 확장 정보 - Properties extendedInfo = ssoModule.getUserExFields(ssoId); + if (prop.isSsoSyncInfo()) { + // 기본 정보 + Properties info = ssoModule.getUserInfos(ssoId); + // 확장 정보 + Properties extendedInfo = ssoModule.getUserExFields(ssoId); - // 필수 필드 검증 - try { - validateRequiredFields(info, extendedInfo); - } catch (IllegalStateException e) { - log.warn("SSO 필수 필드 검증 실패: {}", e.getMessage()); - session.setAttribute("resultMsg", e.getMessage()); - return "redirect:/loginForm.do"; + // 필수 필드 검증 + try { + validateRequiredFields(info, extendedInfo); + } catch (IllegalStateException e) { + log.warn("SSO 필수 필드 검증 실패: {}", e.getMessage()); + session.setAttribute("resultMsg", e.getMessage()); + return "redirect:/loginForm.do"; + } + + // 사용자 정보 로깅 (개인정보 마스킹 처리) + String userId = info.getProperty("USERID"); + String name = info.getProperty("NAME"); + String email = info.getProperty("EMAIL"); + String cellPhoneNo = extendedInfo != null ? extendedInfo.getProperty("CELLPHONENO") : null; + + log.info("SSO 로그인 시도 - userId: {}", userId); + log.debug("SSO 사용자 정보 - userId: {}, name: {}, phone: {}, email: {}", + userId, + MaskingUtils.maskName(name), + maskPhoneNumber(cellPhoneNo), + maskEmail(email)); + + // 사용자 생성 또는 업데이트 + UserInfo userInfo = findOrCreateUser(info, extendedInfo); + + // 로그인 세션 설정 (MainController 위임) + log.info("SSO 로그인 성공 - userId: {}", userId); + return mainController.setupSsoLoginSession(req, userInfo); + } else { + // 동기화 비활성화 모드: 기존 사용자는 업데이트 없이, 신규 사용자는 최소 정보로 생성 + log.info("SSO 동기화 비활성화 모드로 로그인 처리 - ssoId: {}", ssoId); + + UserInfo userInfo = findOrCreateUserWithoutSync(ssoId); + + log.info("SSO 로그인 성공 (동기화 비활성화 모드) - userId: {}", ssoId); + return mainController.setupSsoLoginSession(req, userInfo); } - - // 사용자 정보 로깅 (개인정보 마스킹 처리) - String userId = info.getProperty("USERID"); - String name = info.getProperty("NAME"); - String email = info.getProperty("EMAIL"); - String cellPhoneNo = extendedInfo != null ? extendedInfo.getProperty("CELLPHONENO") : null; - - log.info("SSO 로그인 시도 - userId: {}", userId); - log.debug("SSO 사용자 정보 - userId: {}, name: {}, phone: {}, email: {}", - userId, - MaskingUtils.maskName(name), - maskPhoneNumber(cellPhoneNo), - maskEmail(email)); - - // 사용자 생성 또는 업데이트 - UserInfo userInfo = findOrCreateUser(info, extendedInfo); - - // 로그인 세션 설정 (MainController 위임) - log.info("SSO 로그인 성공 - userId: {}", userId); - return mainController.setupSsoLoginSession(req, userInfo); } } @@ -174,6 +184,52 @@ public class SsoController implements InterceptorSkipController { } } + /** + * 사용자 조회 또는 생성 (동기화 비활성화 모드) + * - 기존 사용자: 정보 업데이트 없이 그대로 반환 + * - 신규 사용자: userId를 username으로 사용하여 최소 정보로 생성 + */ + private UserInfo findOrCreateUserWithoutSync(String ssoId) throws Exception { + // 대소문자 구분 없이 검색 + Optional existingUser = userInfoService.findByUserIdIgnoreCase(ssoId); + + if (existingUser.isPresent()) { + log.debug("동기화 비활성화 모드 - 기존 사용자 발견, 정보 업데이트 없이 로그인 처리: {}", ssoId); + return existingUser.get(); + } else { + return createNewUserWithMinimalInfo(ssoId); + } + } + + /** + * 최소 정보로 신규 사용자 생성 (동기화 비활성화 모드) + * - username을 userId와 동일하게 설정 + */ + private UserInfo createNewUserWithMinimalInfo(String userId) throws Exception { + UserInfo userInfo = new UserInfo(); + userInfo.setUserid(userId); + userInfo.setUsername(userId); // username = userId + userInfo.setPassword(Seed.encrypt("!" + userId)); + userInfo.setRoleidnfiname(CommonConstants.DEPT_DEVELOPER); + + userInfoService.save(userInfo); + + // 기본 역할 할당 + String roleId = monitoringContext.getStringProperty( + MonitoringContext.USER_DEFAULT_RULE, "newbie"); + UserRole userRole = new UserRole(); + userRole.setId(new UserRoleId(userId, roleId)); + userRoleService.save(userRole); + + // 서비스 타입 할당 + DataSourceTypeManager.getDynamicDataSourceTypes().stream() + .map(DataSourceType::getName) + .forEach(type -> userServiceTypeService.insertUserServiceType(userId, type)); + + log.info("동기화 비활성화 모드 - 신규 사용자 생성 완료 (최소 정보): {}", userId); + return userInfo; + } + /** * 신규 사용자 생성 */ diff --git a/src/main/java/com/eactive/eai/rms/onl/apim/obp/ObpApiController.java b/src/main/java/com/eactive/eai/rms/onl/apim/obp/ObpApiController.java index 6faca83..df06370 100644 --- a/src/main/java/com/eactive/eai/rms/onl/apim/obp/ObpApiController.java +++ b/src/main/java/com/eactive/eai/rms/onl/apim/obp/ObpApiController.java @@ -6,6 +6,7 @@ import com.eactive.eai.rms.onl.apim.common.BaseRestController; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.ResponseBody; @@ -42,7 +43,8 @@ public class ObpApiController extends BaseRestController { ) @ResponseBody public String getApis( - @RequestParam(value = "pretty", required = false) Boolean pretty) { + @RequestParam(value = "pretty", required = false) Boolean pretty + ) { log.debug("OBP API 목록 조회 요청: pretty={}", pretty); long startTime = System.currentTimeMillis(); @@ -50,6 +52,7 @@ public class ObpApiController extends BaseRestController { DataSourceContextHolder.setDataSourceType( DataSourceTypeManager.getDataSourceType(DataSourceTypeManager.APIGW)); + try { List apis = obpApiService.findAllApis(); @@ -66,4 +69,46 @@ public class ObpApiController extends BaseRestController { throw e; } } + + /** + * 기관코드별 API 목록 조회 + * + *

해당 기관의 활성 앱(appstatus='1')이 사용하는 API만 반환

+ * + * @param orgCode 기관코드 (OBP 파트너코드) + * @param pretty true면 JSON 들여쓰기 적용 + * @return JSON Array (기관 미존재 시 빈 배열) + */ + @RequestMapping( + value = "/kjb/{orgCode}/apis.json", + produces = JSON_CONTENT_TYPE + ) + @ResponseBody + public String getApisByOrgCode( + @PathVariable("orgCode") String orgCode, + @RequestParam(value = "pretty", required = false) Boolean pretty + ) { + log.debug("OBP API 목록 조회 요청 (기관별): orgCode={}, pretty={}", orgCode, pretty); + long startTime = System.currentTimeMillis(); + + // APIGW 데이터소스 강제 설정 + DataSourceContextHolder.setDataSourceType( + DataSourceTypeManager.getDataSourceType(DataSourceTypeManager.APIGW)); + + try { + List apis = obpApiService.findApisByOrgCode(orgCode); + + String json = toJson(apis, pretty); + + long elapsed = System.currentTimeMillis() - startTime; + log.info("OBP API 목록 조회 완료 (기관별): orgCode={}, count={}, size={}, elapsed={}ms", + orgCode, apis.size(), getFormattedJsonSize(json), elapsed); + + return json; + + } catch (Exception e) { + log.error("OBP API 목록 조회 실패 (기관별): orgCode={}", orgCode, e); + throw e; + } + } } diff --git a/src/main/java/com/eactive/eai/rms/onl/apim/obp/ObpApiService.java b/src/main/java/com/eactive/eai/rms/onl/apim/obp/ObpApiService.java index 54b8b8e..e896067 100644 --- a/src/main/java/com/eactive/eai/rms/onl/apim/obp/ObpApiService.java +++ b/src/main/java/com/eactive/eai/rms/onl/apim/obp/ObpApiService.java @@ -1,7 +1,12 @@ package com.eactive.eai.rms.onl.apim.obp; +import com.eactive.apim.portal.app.entity.Credential; +import com.eactive.apim.portal.app.repository.CredentialRepository; +import com.eactive.apim.portal.apispec.entity.ApiSpecInfo; +import com.eactive.apim.portal.portalorg.entity.PortalOrg; import com.eactive.eai.data.entity.onl.message.QEAIMessageEntity; import com.eactive.eai.data.entity.onl.stdmessage.QStandardMessageInfo; +import com.eactive.eai.rms.data.entity.onl.apim.portalorg.PortalOrgRepository; import com.querydsl.core.Tuple; import com.querydsl.jpa.impl.JPAQueryFactory; import org.apache.commons.lang3.StringUtils; @@ -9,7 +14,10 @@ import org.springframework.stereotype.Service; import javax.persistence.EntityManager; import javax.persistence.PersistenceContext; +import java.util.Collections; import java.util.List; +import java.util.Optional; +import java.util.Set; import java.util.stream.Collectors; /** @@ -23,6 +31,14 @@ public class ObpApiService { @PersistenceContext private EntityManager entityManager; + private final PortalOrgRepository portalOrgRepository; + private final CredentialRepository credentialRepository; + + public ObpApiService(PortalOrgRepository portalOrgRepository, CredentialRepository credentialRepository) { + this.portalOrgRepository = portalOrgRepository; + this.credentialRepository = credentialRepository; + } + private JPAQueryFactory getQueryFactory() { return new JPAQueryFactory(entityManager); } @@ -88,4 +104,60 @@ public class ObpApiService { .authType(authtype) .build(); } + + /** + * 기관코드에 해당하는 법인이 이용하는 API 목록 조회 + * + *

활성 앱(appstatus='1')의 API만 조회

+ * + * @param orgCode 기관코드 (OBP 파트너코드) + * @return API 목록 (기관 미존재 시 빈 리스트) + */ + public List findApisByOrgCode(String orgCode) { + // 1. 기관코드로 기관 조회 + Optional orgOpt = portalOrgRepository.findByOrgCode(orgCode); + if (!orgOpt.isPresent()) { + return Collections.emptyList(); + } + + PortalOrg org = orgOpt.get(); + + // 2. 해당 기관의 활성 앱 조회 (appstatus='1') + List activeApps = credentialRepository.findActiveAppsByOrgIds( + Collections.singletonList(org.getId())); + if (activeApps.isEmpty()) { + return Collections.emptyList(); + } + + // 3. 앱들의 API ID 목록 수집 + Set apiIds = activeApps.stream() + .flatMap(app -> app.getApiList().stream()) + .map(ApiSpecInfo::getApiId) + .collect(Collectors.toSet()); + if (apiIds.isEmpty()) { + return Collections.emptyList(); + } + + // 4. 해당 API만 조회 + QEAIMessageEntity he01 = QEAIMessageEntity.eAIMessageEntity; + QStandardMessageInfo hs04 = QStandardMessageInfo.standardMessageInfo; + + List results = getQueryFactory() + .select( + he01.eaisvcname, + he01.eaisvcdesc, + he01.useyn, + he01.authtype, + hs04.apifullpath + ) + .from(he01) + .leftJoin(hs04).on(he01.eaisvcname.eq(hs04.eaisvcname)) + .where(he01.eaisvcname.in(apiIds)) + .orderBy(he01.eaisvcname.asc()) + .fetch(); + + return results.stream() + .map(this::toDto) + .collect(Collectors.toList()); + } }