인증정보 -> 개발자포탈 정보 반영
This commit is contained in:
@@ -285,6 +285,56 @@
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
$("#btn_sync_portal").click(function() {
|
||||||
|
var clientId = $('input[name=clientId]').val();
|
||||||
|
var clientName = $('input[name=clientName]').val();
|
||||||
|
|
||||||
|
if (!clientId) {
|
||||||
|
alert("Client ID가 없습니다.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!confirm("'" + clientName + "'의 개발자포탈 정보를 반영하시겠습니까?\n\n" +
|
||||||
|
"APIGW 인증 정보를 포탈 DB에 반영합니다. (없으면 생성, 있으면 업데이트)")) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$.ajax({
|
||||||
|
type: "POST",
|
||||||
|
url: url,
|
||||||
|
dataType: "json",
|
||||||
|
data: {
|
||||||
|
cmd: 'SYNC_PORTAL',
|
||||||
|
clientId: clientId
|
||||||
|
},
|
||||||
|
success: function(response) {
|
||||||
|
if (response.success) {
|
||||||
|
var msg = "포탈 정보 반영 완료";
|
||||||
|
|
||||||
|
if (response.action === 'INSERTED') {
|
||||||
|
msg = "포탈 정보를 새로 생성했습니다.";
|
||||||
|
} else if (response.action === 'UPDATED') {
|
||||||
|
msg = "포탈 정보를 업데이트했습니다.";
|
||||||
|
} else if (response.action === 'SKIPPED_NO_ORG') {
|
||||||
|
msg = "반영을 건너뜁니다.\n법인(orgId)이 설정되지 않은 클라이언트입니다.";
|
||||||
|
} else if (response.action === 'SKIPPED_INVALID_API') {
|
||||||
|
msg = "반영을 건너뜁니다.\n존재하지 않는 API가 포함되어 있습니다.\n\n";
|
||||||
|
if (response.invalidApis && response.invalidApis.length > 0) {
|
||||||
|
msg += "누락된 API: " + response.invalidApis.join(", ");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
alert(msg);
|
||||||
|
} else {
|
||||||
|
alert("반영 실패\n\n" + response.message);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
error: function(xhr) {
|
||||||
|
alert("반영 중 오류가 발생했습니다.");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
$("#btn_popup_api").click(function () {
|
$("#btn_popup_api").click(function () {
|
||||||
const args = {};
|
const args = {};
|
||||||
const url2 = api_url_view += "?cmd=POPUP";
|
const url2 = api_url_view += "?cmd=POPUP";
|
||||||
@@ -417,6 +467,8 @@
|
|||||||
</div><!-- end content_top -->
|
</div><!-- end content_top -->
|
||||||
<div class="content_middle">
|
<div class="content_middle">
|
||||||
<div class="search_wrap">
|
<div class="search_wrap">
|
||||||
|
<button type="button" class="cssbtn" id="btn_sync_portal" level="W" status="DETAIL"><i class="material-icons">sync</i> 개발자포탈 정보 반영
|
||||||
|
</button>
|
||||||
<button type="button" class="cssbtn" id="btn_delete" level="W" status="DETAIL"><i class="material-icons">delete</i> <%= localeMessage.getString("button.delete") %>
|
<button type="button" class="cssbtn" id="btn_delete" level="W" status="DETAIL"><i class="material-icons">delete</i> <%= localeMessage.getString("button.delete") %>
|
||||||
</button>
|
</button>
|
||||||
<button type="button" class="cssbtn" id="btn_modify" level="W" status="DETAIL,NEW"><i
|
<button type="button" class="cssbtn" id="btn_modify" level="W" status="DETAIL,NEW"><i
|
||||||
|
|||||||
@@ -55,4 +55,6 @@ public class CredentialUI implements Serializable, com.eactive.eai.data.Data {
|
|||||||
private List<ApiSpecInfoUI> apiList = new ArrayList<>();
|
private List<ApiSpecInfoUI> apiList = new ArrayList<>();
|
||||||
|
|
||||||
private String appIconFileId;
|
private String appIconFileId;
|
||||||
|
|
||||||
|
private String appDescription;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -121,4 +121,37 @@ public class ClientController extends OnlBaseAnnotationController {
|
|||||||
response.put("hasMtls", hasMtls);
|
response.put("hasMtls", hasMtls);
|
||||||
return ResponseEntity.ok(response);
|
return ResponseEntity.ok(response);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* APIGW 인증관리 정보를 개발자포탈에 반영합니다.
|
||||||
|
* 포탈에 없으면 신규 생성, 있으면 업데이트합니다.
|
||||||
|
*
|
||||||
|
* @param clientId 클라이언트 ID
|
||||||
|
* @return 반영 결과 (success, action, message, invalidApis)
|
||||||
|
*/
|
||||||
|
@PostMapping(value = "/onl/admin/authserver/clientMan.json", params = "cmd=SYNC_PORTAL")
|
||||||
|
public ResponseEntity<Map<String, Object>> syncPortalData(String clientId) {
|
||||||
|
try {
|
||||||
|
SyncResult result = clientManService.syncPortalData(clientId);
|
||||||
|
|
||||||
|
Map<String, Object> response = new HashMap<>();
|
||||||
|
response.put("success", result.isSuccess());
|
||||||
|
response.put("message", result.getMessage());
|
||||||
|
response.put("action", result.getAction().name());
|
||||||
|
|
||||||
|
// 유효하지 않은 API 목록 포함
|
||||||
|
if (result.getInvalidApis() != null && !result.getInvalidApis().isEmpty()) {
|
||||||
|
response.put("invalidApis", result.getInvalidApis());
|
||||||
|
}
|
||||||
|
|
||||||
|
return ResponseEntity.ok(response);
|
||||||
|
} catch (Exception e) {
|
||||||
|
// 에러 처리
|
||||||
|
Map<String, Object> error = new HashMap<>();
|
||||||
|
error.put("success", false);
|
||||||
|
error.put("message", "반영 중 오류: " + e.getMessage());
|
||||||
|
error.put("action", "ERROR");
|
||||||
|
return ResponseEntity.status(500).body(error);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+180
-1
@@ -1,9 +1,20 @@
|
|||||||
package com.eactive.eai.rms.onl.manage.authserver.client;
|
package com.eactive.eai.rms.onl.manage.authserver.client;
|
||||||
|
|
||||||
|
import com.eactive.apim.portal.app.entity.Credential;
|
||||||
import com.eactive.apim.portal.portalorg.entity.PortalOrg;
|
import com.eactive.apim.portal.portalorg.entity.PortalOrg;
|
||||||
|
import com.eactive.eai.data.entity.onl.eaimsg.EAIMessageEntity;
|
||||||
|
import com.eactive.eai.rms.common.datasource.DataSourceContextHolder;
|
||||||
|
import com.eactive.eai.rms.common.datasource.DataSourceType;
|
||||||
|
import com.eactive.eai.rms.common.datasource.DataSourceTypeManager;
|
||||||
import com.eactive.eai.rms.data.entity.onl.apim.portalorg.PortalOrgService;
|
import com.eactive.eai.rms.data.entity.onl.apim.portalorg.PortalOrgService;
|
||||||
|
import com.eactive.eai.rms.data.entity.onl.eaimsg.EAIMessageRepository;
|
||||||
|
import com.eactive.eai.rms.onl.apim.approval.credential.CredentialManService;
|
||||||
|
import com.eactive.eai.rms.onl.apim.approval.credential.CredentialService;
|
||||||
|
import com.eactive.eai.rms.onl.apim.approval.credential.CredentialUI;
|
||||||
import com.eactive.eai.rms.onl.apim.portalorg.PortalOrgUI;
|
import com.eactive.eai.rms.onl.apim.portalorg.PortalOrgUI;
|
||||||
import com.eactive.eai.rms.onl.apim.portalorg.PortalOrgUIMapper;
|
import com.eactive.eai.rms.onl.apim.portalorg.PortalOrgUIMapper;
|
||||||
|
import com.eactive.eai.rms.onl.transaction.apim.ui.ApiSpecInfoUI;
|
||||||
|
import org.apache.commons.lang3.StringUtils;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.data.domain.Page;
|
import org.springframework.data.domain.Page;
|
||||||
import org.springframework.data.domain.Pageable;
|
import org.springframework.data.domain.Pageable;
|
||||||
@@ -15,8 +26,10 @@ import com.eactive.eai.rms.common.base.OnlBaseService;
|
|||||||
import com.eactive.eai.rms.data.entity.onl.authserver.ClientEntityService;
|
import com.eactive.eai.rms.data.entity.onl.authserver.ClientEntityService;
|
||||||
import com.eactive.eai.rms.data.entity.onl.authserver.ClientSearch;
|
import com.eactive.eai.rms.data.entity.onl.authserver.ClientSearch;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Optional;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
@Service
|
@Service
|
||||||
@@ -27,16 +40,25 @@ public class ClientManService extends OnlBaseService {
|
|||||||
private ClientUIMapper clientUIMapper;
|
private ClientUIMapper clientUIMapper;
|
||||||
private PortalOrgService portalOrgService;
|
private PortalOrgService portalOrgService;
|
||||||
private PortalOrgUIMapper portalOrgUIMapper;
|
private PortalOrgUIMapper portalOrgUIMapper;
|
||||||
|
private CredentialManService credentialManService;
|
||||||
|
private CredentialService credentialService;
|
||||||
|
private EAIMessageRepository eaiMessageRepository;
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
public ClientManService(ClientEntityService clientEntityService,
|
public ClientManService(ClientEntityService clientEntityService,
|
||||||
ClientUIMapper clientUIMapper,
|
ClientUIMapper clientUIMapper,
|
||||||
PortalOrgService portalOrgService,
|
PortalOrgService portalOrgService,
|
||||||
PortalOrgUIMapper portalOrgUIMapper) {
|
PortalOrgUIMapper portalOrgUIMapper,
|
||||||
|
CredentialManService credentialManService,
|
||||||
|
CredentialService credentialService,
|
||||||
|
EAIMessageRepository eaiMessageRepository) {
|
||||||
this.clientEntityService = clientEntityService;
|
this.clientEntityService = clientEntityService;
|
||||||
this.clientUIMapper = clientUIMapper;
|
this.clientUIMapper = clientUIMapper;
|
||||||
this.portalOrgService = portalOrgService;
|
this.portalOrgService = portalOrgService;
|
||||||
this.portalOrgUIMapper = portalOrgUIMapper;
|
this.portalOrgUIMapper = portalOrgUIMapper;
|
||||||
|
this.credentialManService = credentialManService;
|
||||||
|
this.credentialService = credentialService;
|
||||||
|
this.eaiMessageRepository = eaiMessageRepository;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -83,4 +105,161 @@ public class ClientManService extends OnlBaseService {
|
|||||||
.map(ClientEntity::getClientid)
|
.map(ClientEntity::getClientid)
|
||||||
.collect(Collectors.toList());
|
.collect(Collectors.toList());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* AGW 인증관리(ClientEntity)의 정보를 개발자포탈(Credential)에 반영합니다.
|
||||||
|
* 포탈에 없으면 신규 생성(INSERT), 있으면 업데이트(UPDATE)합니다.
|
||||||
|
*
|
||||||
|
* @param clientId 클라이언트 ID
|
||||||
|
* @return 반영 결과 (INSERTED, UPDATED, SKIPPED_NO_ORG, SKIPPED_INVALID_API, ERROR)
|
||||||
|
*/
|
||||||
|
public SyncResult syncPortalData(String clientId) {
|
||||||
|
try {
|
||||||
|
// 1. APIGW 스키마에서 ClientEntity 조회
|
||||||
|
ClientEntity clientEntity = clientEntityService.getById(clientId);
|
||||||
|
|
||||||
|
// 2. 유효성 검증 - orgId 확인
|
||||||
|
String orgId = clientEntity.getOrgid();
|
||||||
|
if (StringUtils.isBlank(orgId)) {
|
||||||
|
return SyncResult.builder()
|
||||||
|
.success(false)
|
||||||
|
.action(SyncResult.SyncAction.SKIPPED_NO_ORG)
|
||||||
|
.message("법인(orgId)이 설정되지 않은 클라이언트입니다.")
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
// 3. API 유효성 검증 (APIGW 스키마)
|
||||||
|
List<String> invalidApis = new ArrayList<>();
|
||||||
|
if (clientEntity.getApiList() != null) {
|
||||||
|
for (EAIMessageEntity apiEntity : clientEntity.getApiList()) {
|
||||||
|
String eaiSvcName = apiEntity.getEaiSvcName();
|
||||||
|
// APIGW에 실제 API 존재하는지 확인
|
||||||
|
if (!eaiMessageRepository.existsById(eaiSvcName)) {
|
||||||
|
invalidApis.add(eaiSvcName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 유효하지 않은 API가 있으면 반영 중단
|
||||||
|
if (!invalidApis.isEmpty()) {
|
||||||
|
return SyncResult.builder()
|
||||||
|
.success(false)
|
||||||
|
.action(SyncResult.SyncAction.SKIPPED_INVALID_API)
|
||||||
|
.invalidApis(invalidApis)
|
||||||
|
.message("존재하지 않는 API: " + String.join(", ", invalidApis))
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
// 4. MONITORING 스키마로 전환
|
||||||
|
DataSourceType monitoringType = DataSourceTypeManager.getDataSourceType("MONITORING");
|
||||||
|
DataSourceContextHolder.setDataSourceType(monitoringType);
|
||||||
|
|
||||||
|
// 5. 기존 Credential 확인
|
||||||
|
Optional<Credential> existingCredential = credentialService.getRepository()
|
||||||
|
.findOne((root, query, cb) -> cb.and(
|
||||||
|
cb.equal(root.get("clientid"), clientId),
|
||||||
|
cb.equal(root.get("orgid"), orgId)
|
||||||
|
));
|
||||||
|
|
||||||
|
// 6. 데이터 변환 (ClientEntity → CredentialUI)
|
||||||
|
CredentialUI credentialUI = convertToCredentialUI(clientEntity);
|
||||||
|
|
||||||
|
SyncResult.SyncAction action;
|
||||||
|
if (existingCredential.isPresent()) {
|
||||||
|
// 업데이트: 기존 값 유지해야 할 필드 처리
|
||||||
|
Credential existing = existingCredential.get();
|
||||||
|
if (StringUtils.isNotBlank(existing.getAppDescription())) {
|
||||||
|
credentialUI.setAppDescription(existing.getAppDescription());
|
||||||
|
}
|
||||||
|
if (StringUtils.isNotBlank(existing.getAppIconFileId())) {
|
||||||
|
credentialUI.setAppIconFileId(existing.getAppIconFileId());
|
||||||
|
}
|
||||||
|
if (StringUtils.isNotBlank(existing.getServer())) {
|
||||||
|
credentialUI.setServer(existing.getServer());
|
||||||
|
}
|
||||||
|
|
||||||
|
// 7. 포탈 스키마에 업데이트
|
||||||
|
credentialManService.update(credentialUI);
|
||||||
|
action = SyncResult.SyncAction.UPDATED;
|
||||||
|
} else {
|
||||||
|
// 신규 생성: 기본값 설정
|
||||||
|
if (StringUtils.isBlank(credentialUI.getAppDescription())) {
|
||||||
|
credentialUI.setAppDescription("APIGW에서 반영된 인증정보");
|
||||||
|
}
|
||||||
|
|
||||||
|
// 7. 포탈 스키마에 신규 생성
|
||||||
|
credentialManService.insert(credentialUI);
|
||||||
|
action = SyncResult.SyncAction.INSERTED;
|
||||||
|
}
|
||||||
|
|
||||||
|
return SyncResult.builder()
|
||||||
|
.success(true)
|
||||||
|
.action(action)
|
||||||
|
.message("포탈 정보 반영 완료")
|
||||||
|
.build();
|
||||||
|
|
||||||
|
} catch (Exception e) {
|
||||||
|
logger.error("포탈 정보 반영 중 오류 발생", e);
|
||||||
|
return SyncResult.builder()
|
||||||
|
.success(false)
|
||||||
|
.action(SyncResult.SyncAction.ERROR)
|
||||||
|
.message("반영 중 오류: " + e.getMessage())
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ClientEntity를 CredentialUI로 변환합니다.
|
||||||
|
*
|
||||||
|
* @param clientEntity APIGW 클라이언트 엔티티
|
||||||
|
* @return CredentialUI 포탈 인증정보 UI 객체
|
||||||
|
*/
|
||||||
|
private CredentialUI convertToCredentialUI(ClientEntity clientEntity) {
|
||||||
|
CredentialUI credentialUI = new CredentialUI();
|
||||||
|
|
||||||
|
// 기본 인증정보
|
||||||
|
credentialUI.setClientid(clientEntity.getClientid());
|
||||||
|
credentialUI.setClientname(clientEntity.getClientname());
|
||||||
|
credentialUI.setClientsecret(clientEntity.getClientsecret());
|
||||||
|
|
||||||
|
// OAuth 설정
|
||||||
|
credentialUI.setScope(clientEntity.getScope());
|
||||||
|
credentialUI.setGranttypes(clientEntity.getGranttypes());
|
||||||
|
credentialUI.setAccesstokenvalidityseconds(clientEntity.getAccesstokenvalidityseconds());
|
||||||
|
credentialUI.setRefreshtokenvalidityseconds(clientEntity.getRefreshtokenvalidityseconds());
|
||||||
|
|
||||||
|
// 보안 설정
|
||||||
|
credentialUI.setAllowedips(clientEntity.getAllowedips());
|
||||||
|
credentialUI.setAuthorities(clientEntity.getAuthorities());
|
||||||
|
credentialUI.setRedirecturi(clientEntity.getRedirecturi());
|
||||||
|
credentialUI.setSecuritykey(clientEntity.getSecuritykey());
|
||||||
|
credentialUI.setAutoapprove(clientEntity.getAutoapprove());
|
||||||
|
credentialUI.setResourceids(clientEntity.getResourceids());
|
||||||
|
|
||||||
|
// 조직 정보
|
||||||
|
credentialUI.setOrgid(clientEntity.getOrgid());
|
||||||
|
credentialUI.setOrgname(clientEntity.getOrgname());
|
||||||
|
|
||||||
|
// 앱 상태
|
||||||
|
credentialUI.setAppstatus(clientEntity.getAppstatus());
|
||||||
|
credentialUI.setDailytokenlimit(Integer.parseInt(
|
||||||
|
StringUtils.defaultIfBlank(clientEntity.getDailytokenlimit(), "0")));
|
||||||
|
|
||||||
|
// 수정 정보
|
||||||
|
credentialUI.setModifiedby(clientEntity.getModifiedby());
|
||||||
|
credentialUI.setModifiedon(clientEntity.getModifiedon());
|
||||||
|
|
||||||
|
// API 목록 변환
|
||||||
|
List<ApiSpecInfoUI> apiList = new ArrayList<>();
|
||||||
|
if (clientEntity.getApiList() != null) {
|
||||||
|
for (EAIMessageEntity apiEntity : clientEntity.getApiList()) {
|
||||||
|
ApiSpecInfoUI apiUI = new ApiSpecInfoUI();
|
||||||
|
apiUI.setApiId(apiEntity.getEaiSvcName());
|
||||||
|
apiList.add(apiUI);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
credentialUI.setApiList(apiList);
|
||||||
|
|
||||||
|
return credentialUI;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,68 @@
|
|||||||
|
package com.eactive.eai.rms.onl.manage.authserver.client;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Builder;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 개발자포탈 정보 반영 결과 DTO
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@Builder
|
||||||
|
@NoArgsConstructor
|
||||||
|
@AllArgsConstructor
|
||||||
|
public class SyncResult {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 반영 성공 여부
|
||||||
|
*/
|
||||||
|
private boolean success;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 결과 메시지
|
||||||
|
*/
|
||||||
|
private String message;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 반영 액션 타입
|
||||||
|
*/
|
||||||
|
private SyncAction action;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 존재하지 않는 API 목록 (SKIPPED_INVALID_API인 경우)
|
||||||
|
*/
|
||||||
|
private List<String> invalidApis;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 반영 액션 타입
|
||||||
|
*/
|
||||||
|
public enum SyncAction {
|
||||||
|
/**
|
||||||
|
* 신규 생성
|
||||||
|
*/
|
||||||
|
INSERTED,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 기존 데이터 업데이트
|
||||||
|
*/
|
||||||
|
UPDATED,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* orgId 없어서 건너뜀
|
||||||
|
*/
|
||||||
|
SKIPPED_NO_ORG,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 유효하지 않은 API 존재로 건너뜀
|
||||||
|
*/
|
||||||
|
SKIPPED_INVALID_API,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 오류 발생
|
||||||
|
*/
|
||||||
|
ERROR
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user