Add API retrieval by organization code and enhance SSO user handling
- Implemented `getApisByOrgCode` method in `ObpApiService` to fetch APIs based on organization code. - Added corresponding endpoint in `ObpApiController`. - Updated `SsoController` to handle user creation without synchronization for existing users. - Introduced new properties for SSO synchronization settings in `KjbProperty`.
This commit is contained in:
@@ -5,6 +5,7 @@
|
|||||||
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
|
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
|
||||||
<%@ taglib uri="http://www.springframework.org/tags" prefix="spring"%>
|
<%@ taglib uri="http://www.springframework.org/tags" prefix="spring"%>
|
||||||
<%@ include file="/jsp/common/include/localemessage.jsp" %>
|
<%@ include file="/jsp/common/include/localemessage.jsp" %>
|
||||||
|
<c:set var="themeColor" value="<%=System.getProperty(\"theme.color\")%>" scope="session" />
|
||||||
|
|
||||||
<%
|
<%
|
||||||
String topPage = request.getContextPath() + StringUtils.defaultString((String) request.getAttribute("topPage"), "/top_04.do");
|
String topPage = request.getContextPath() + StringUtils.defaultString((String) request.getAttribute("topPage"), "/top_04.do");
|
||||||
|
|||||||
+8
@@ -4,7 +4,15 @@ import com.eactive.apim.portal.portalorg.entity.PortalOrg;
|
|||||||
import com.eactive.eai.data.jpa.BaseRepository;
|
import com.eactive.eai.data.jpa.BaseRepository;
|
||||||
import com.eactive.eai.rms.data.EMSDataSource;
|
import com.eactive.eai.rms.data.EMSDataSource;
|
||||||
|
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
@EMSDataSource
|
@EMSDataSource
|
||||||
public interface PortalOrgRepository extends BaseRepository<PortalOrg, String> {
|
public interface PortalOrgRepository extends BaseRepository<PortalOrg, String> {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 기관코드로 기관 조회
|
||||||
|
* @param orgCode 기관코드 (OBP 파트너코드)
|
||||||
|
* @return 기관 정보
|
||||||
|
*/
|
||||||
|
Optional<PortalOrg> findByOrgCode(String orgCode);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -106,39 +106,49 @@ public class SsoController implements InterceptorSkipController {
|
|||||||
return "redirect:/loginForm.do";
|
return "redirect:/loginForm.do";
|
||||||
}
|
}
|
||||||
|
|
||||||
// 기본 정보
|
if (prop.isSsoSyncInfo()) {
|
||||||
Properties info = ssoModule.getUserInfos(ssoId);
|
// 기본 정보
|
||||||
// 확장 정보
|
Properties info = ssoModule.getUserInfos(ssoId);
|
||||||
Properties extendedInfo = ssoModule.getUserExFields(ssoId);
|
// 확장 정보
|
||||||
|
Properties extendedInfo = ssoModule.getUserExFields(ssoId);
|
||||||
|
|
||||||
// 필수 필드 검증
|
// 필수 필드 검증
|
||||||
try {
|
try {
|
||||||
validateRequiredFields(info, extendedInfo);
|
validateRequiredFields(info, extendedInfo);
|
||||||
} catch (IllegalStateException e) {
|
} catch (IllegalStateException e) {
|
||||||
log.warn("SSO 필수 필드 검증 실패: {}", e.getMessage());
|
log.warn("SSO 필수 필드 검증 실패: {}", e.getMessage());
|
||||||
session.setAttribute("resultMsg", e.getMessage());
|
session.setAttribute("resultMsg", e.getMessage());
|
||||||
return "redirect:/loginForm.do";
|
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<UserInfo> 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;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 신규 사용자 생성
|
* 신규 사용자 생성
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import com.eactive.eai.rms.onl.apim.common.BaseRestController;
|
|||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
import org.springframework.stereotype.Controller;
|
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.RequestMapping;
|
||||||
import org.springframework.web.bind.annotation.RequestParam;
|
import org.springframework.web.bind.annotation.RequestParam;
|
||||||
import org.springframework.web.bind.annotation.ResponseBody;
|
import org.springframework.web.bind.annotation.ResponseBody;
|
||||||
@@ -42,7 +43,8 @@ public class ObpApiController extends BaseRestController {
|
|||||||
)
|
)
|
||||||
@ResponseBody
|
@ResponseBody
|
||||||
public String getApis(
|
public String getApis(
|
||||||
@RequestParam(value = "pretty", required = false) Boolean pretty) {
|
@RequestParam(value = "pretty", required = false) Boolean pretty
|
||||||
|
) {
|
||||||
log.debug("OBP API 목록 조회 요청: pretty={}", pretty);
|
log.debug("OBP API 목록 조회 요청: pretty={}", pretty);
|
||||||
long startTime = System.currentTimeMillis();
|
long startTime = System.currentTimeMillis();
|
||||||
|
|
||||||
@@ -50,6 +52,7 @@ public class ObpApiController extends BaseRestController {
|
|||||||
DataSourceContextHolder.setDataSourceType(
|
DataSourceContextHolder.setDataSourceType(
|
||||||
DataSourceTypeManager.getDataSourceType(DataSourceTypeManager.APIGW));
|
DataSourceTypeManager.getDataSourceType(DataSourceTypeManager.APIGW));
|
||||||
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
List<ObpApiDTO> apis = obpApiService.findAllApis();
|
List<ObpApiDTO> apis = obpApiService.findAllApis();
|
||||||
|
|
||||||
@@ -66,4 +69,46 @@ public class ObpApiController extends BaseRestController {
|
|||||||
throw e;
|
throw e;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 기관코드별 API 목록 조회
|
||||||
|
*
|
||||||
|
* <p>해당 기관의 활성 앱(appstatus='1')이 사용하는 API만 반환</p>
|
||||||
|
*
|
||||||
|
* @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<ObpApiDTO> 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,12 @@
|
|||||||
package com.eactive.eai.rms.onl.apim.obp;
|
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.message.QEAIMessageEntity;
|
||||||
import com.eactive.eai.data.entity.onl.stdmessage.QStandardMessageInfo;
|
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.core.Tuple;
|
||||||
import com.querydsl.jpa.impl.JPAQueryFactory;
|
import com.querydsl.jpa.impl.JPAQueryFactory;
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
@@ -9,7 +14,10 @@ import org.springframework.stereotype.Service;
|
|||||||
|
|
||||||
import javax.persistence.EntityManager;
|
import javax.persistence.EntityManager;
|
||||||
import javax.persistence.PersistenceContext;
|
import javax.persistence.PersistenceContext;
|
||||||
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Optional;
|
||||||
|
import java.util.Set;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -23,6 +31,14 @@ public class ObpApiService {
|
|||||||
@PersistenceContext
|
@PersistenceContext
|
||||||
private EntityManager entityManager;
|
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() {
|
private JPAQueryFactory getQueryFactory() {
|
||||||
return new JPAQueryFactory(entityManager);
|
return new JPAQueryFactory(entityManager);
|
||||||
}
|
}
|
||||||
@@ -88,4 +104,60 @@ public class ObpApiService {
|
|||||||
.authType(authtype)
|
.authType(authtype)
|
||||||
.build();
|
.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 기관코드에 해당하는 법인이 이용하는 API 목록 조회
|
||||||
|
*
|
||||||
|
* <p>활성 앱(appstatus='1')의 API만 조회</p>
|
||||||
|
*
|
||||||
|
* @param orgCode 기관코드 (OBP 파트너코드)
|
||||||
|
* @return API 목록 (기관 미존재 시 빈 리스트)
|
||||||
|
*/
|
||||||
|
public List<ObpApiDTO> findApisByOrgCode(String orgCode) {
|
||||||
|
// 1. 기관코드로 기관 조회
|
||||||
|
Optional<PortalOrg> orgOpt = portalOrgRepository.findByOrgCode(orgCode);
|
||||||
|
if (!orgOpt.isPresent()) {
|
||||||
|
return Collections.emptyList();
|
||||||
|
}
|
||||||
|
|
||||||
|
PortalOrg org = orgOpt.get();
|
||||||
|
|
||||||
|
// 2. 해당 기관의 활성 앱 조회 (appstatus='1')
|
||||||
|
List<Credential> activeApps = credentialRepository.findActiveAppsByOrgIds(
|
||||||
|
Collections.singletonList(org.getId()));
|
||||||
|
if (activeApps.isEmpty()) {
|
||||||
|
return Collections.emptyList();
|
||||||
|
}
|
||||||
|
|
||||||
|
// 3. 앱들의 API ID 목록 수집
|
||||||
|
Set<String> 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<Tuple> 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());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user