db
This commit is contained in:
+314
@@ -0,0 +1,314 @@
|
||||
package com.eactive.eai.rms.common.dbconsole.controller;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.security.access.AccessDeniedException;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.ui.Model;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.ResponseBody;
|
||||
|
||||
import com.eactive.eai.rms.common.interceptor.InterceptorSkipController;
|
||||
import com.eactive.eai.rms.common.login.LoginVo;
|
||||
import com.eactive.eai.rms.common.login.SessionManager;
|
||||
import com.eactive.eai.rms.common.dbconsole.dto.ColumnInfoDto;
|
||||
import com.eactive.eai.rms.common.dbconsole.dto.DatasourceInfoDto;
|
||||
import com.eactive.eai.rms.common.dbconsole.dto.SqlRequestDto;
|
||||
import com.eactive.eai.rms.common.dbconsole.dto.SqlResultDto;
|
||||
import com.eactive.eai.rms.common.dbconsole.dto.TableInfoDto;
|
||||
import com.eactive.eai.rms.common.dbconsole.service.DbConsoleDecryptService;
|
||||
import com.eactive.eai.rms.common.dbconsole.service.DbConsoleService;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
|
||||
/**
|
||||
* DB Console Controller
|
||||
* - admin 그룹 사용자만 접근 가능
|
||||
*/
|
||||
@Controller
|
||||
@RequestMapping("/admin/dbconsole")
|
||||
public class DbConsoleController implements InterceptorSkipController {
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger(DbConsoleController.class);
|
||||
|
||||
private final DbConsoleService dbConsoleService;
|
||||
private final DbConsoleDecryptService decryptService;
|
||||
private final ObjectMapper objectMapper;
|
||||
|
||||
public DbConsoleController(DbConsoleService dbConsoleService, DbConsoleDecryptService decryptService) {
|
||||
this.dbConsoleService = dbConsoleService;
|
||||
this.decryptService = decryptService;
|
||||
this.objectMapper = new ObjectMapper();
|
||||
}
|
||||
|
||||
/**
|
||||
* Admin Role 권한 체크
|
||||
*/
|
||||
private void checkAdminAccess(HttpServletRequest request) {
|
||||
LoginVo loginVo = SessionManager.getLoginVo(request);
|
||||
if (loginVo == null) {
|
||||
throw new AccessDeniedException("로그인이 필요합니다.");
|
||||
}
|
||||
|
||||
List<String> roleList = loginVo.getRoleList();
|
||||
if (roleList == null || roleList.isEmpty()) {
|
||||
log.warn("DB Console 접근 거부 (역할 없음): userId={}", loginVo.getUserId());
|
||||
throw new AccessDeniedException("DB Console 접근 권한이 없습니다.");
|
||||
}
|
||||
|
||||
// admin 역할 체크
|
||||
boolean hasAdminRole = roleList.stream()
|
||||
.anyMatch(role -> role != null &&
|
||||
("ADMIN".equalsIgnoreCase(role) || role.toUpperCase().contains("ADMIN")));
|
||||
|
||||
if (!hasAdminRole) {
|
||||
log.warn("DB Console 접근 거부 (Admin 권한 없음): userId={}, roles={}",
|
||||
loginVo.getUserId(), roleList);
|
||||
throw new AccessDeniedException("DB Console 접근 권한이 없습니다. (Admin 권한 필요)");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* DB Console 페이지
|
||||
*/
|
||||
@GetMapping("/console.do")
|
||||
public String dbConsolePage(HttpServletRequest request, Model model) {
|
||||
checkAdminAccess(request);
|
||||
|
||||
try {
|
||||
List<DatasourceInfoDto> datasources = dbConsoleService.getAvailableDatasources();
|
||||
String sessionId = dbConsoleService.createSession();
|
||||
|
||||
model.addAttribute("datasources", datasources);
|
||||
model.addAttribute("datasourcesJson", objectMapper.writeValueAsString(datasources));
|
||||
model.addAttribute("sessionId", sessionId);
|
||||
} catch (Exception e) {
|
||||
log.error("DB Console 페이지 로드 오류", e);
|
||||
model.addAttribute("datasourcesJson", "[]");
|
||||
model.addAttribute("sessionId", "");
|
||||
}
|
||||
|
||||
return "/common/dbconsole/dbConsoleMan";
|
||||
}
|
||||
|
||||
/**
|
||||
* 사용 가능한 데이터소스 목록 조회
|
||||
*/
|
||||
@PostMapping("/datasources.do")
|
||||
@ResponseBody
|
||||
public ResponseEntity<List<DatasourceInfoDto>> getDatasources(HttpServletRequest request) {
|
||||
checkAdminAccess(request);
|
||||
return ResponseEntity.ok(dbConsoleService.getAvailableDatasources());
|
||||
}
|
||||
|
||||
/**
|
||||
* 새 세션 생성
|
||||
*/
|
||||
@PostMapping("/session.do")
|
||||
@ResponseBody
|
||||
public ResponseEntity<Map<String, String>> createSession(HttpServletRequest request) {
|
||||
checkAdminAccess(request);
|
||||
String sessionId = dbConsoleService.createSession();
|
||||
Map<String, String> result = new HashMap<>();
|
||||
result.put("sessionId", sessionId);
|
||||
return ResponseEntity.ok(result);
|
||||
}
|
||||
|
||||
/**
|
||||
* SQL 실행
|
||||
*/
|
||||
@PostMapping("/execute.do")
|
||||
@ResponseBody
|
||||
public ResponseEntity<SqlResultDto> executeSql(HttpServletRequest request, @RequestBody SqlRequestDto sqlRequest) {
|
||||
checkAdminAccess(request);
|
||||
log.debug("SQL 실행 요청: session={}, action={}", sqlRequest.getSessionId(), sqlRequest.getAction());
|
||||
SqlResultDto result = dbConsoleService.executeSql(sqlRequest);
|
||||
return ResponseEntity.ok(result);
|
||||
}
|
||||
|
||||
/**
|
||||
* COMMIT
|
||||
*/
|
||||
@PostMapping("/commit.do")
|
||||
@ResponseBody
|
||||
public ResponseEntity<SqlResultDto> commit(HttpServletRequest request, @RequestBody SqlRequestDto sqlRequest) {
|
||||
checkAdminAccess(request);
|
||||
sqlRequest.setAction("COMMIT");
|
||||
SqlResultDto result = dbConsoleService.executeSql(sqlRequest);
|
||||
return ResponseEntity.ok(result);
|
||||
}
|
||||
|
||||
/**
|
||||
* ROLLBACK
|
||||
*/
|
||||
@PostMapping("/rollback.do")
|
||||
@ResponseBody
|
||||
public ResponseEntity<SqlResultDto> rollback(HttpServletRequest request, @RequestBody SqlRequestDto sqlRequest) {
|
||||
checkAdminAccess(request);
|
||||
sqlRequest.setAction("ROLLBACK");
|
||||
SqlResultDto result = dbConsoleService.executeSql(sqlRequest);
|
||||
return ResponseEntity.ok(result);
|
||||
}
|
||||
|
||||
/**
|
||||
* 세션 종료
|
||||
*/
|
||||
@PostMapping("/disconnect.do")
|
||||
@ResponseBody
|
||||
public ResponseEntity<SqlResultDto> disconnect(HttpServletRequest request, @RequestBody SqlRequestDto sqlRequest) {
|
||||
checkAdminAccess(request);
|
||||
sqlRequest.setAction("DISCONNECT");
|
||||
SqlResultDto result = dbConsoleService.executeSql(sqlRequest);
|
||||
return ResponseEntity.ok(result);
|
||||
}
|
||||
|
||||
/**
|
||||
* 스키마 목록 조회
|
||||
*/
|
||||
@PostMapping("/schemas.do")
|
||||
@ResponseBody
|
||||
public ResponseEntity<List<String>> getSchemas(HttpServletRequest request, @RequestBody SqlRequestDto sqlRequest) {
|
||||
checkAdminAccess(request);
|
||||
List<String> schemas = dbConsoleService.getSchemas(sqlRequest);
|
||||
return ResponseEntity.ok(schemas);
|
||||
}
|
||||
|
||||
/**
|
||||
* 테이블 목록 조회
|
||||
*/
|
||||
@PostMapping("/tables.do")
|
||||
@ResponseBody
|
||||
public ResponseEntity<List<TableInfoDto>> getTables(HttpServletRequest request, @RequestBody SqlRequestDto sqlRequest) {
|
||||
checkAdminAccess(request);
|
||||
List<TableInfoDto> tables = dbConsoleService.getTables(sqlRequest);
|
||||
return ResponseEntity.ok(tables);
|
||||
}
|
||||
|
||||
/**
|
||||
* 테이블 컬럼 정보 조회
|
||||
*/
|
||||
@PostMapping("/columns.do")
|
||||
@ResponseBody
|
||||
public ResponseEntity<List<ColumnInfoDto>> getColumns(HttpServletRequest request, @RequestBody SqlRequestDto sqlRequest) {
|
||||
checkAdminAccess(request);
|
||||
List<ColumnInfoDto> columns = dbConsoleService.getColumns(sqlRequest);
|
||||
return ResponseEntity.ok(columns);
|
||||
}
|
||||
|
||||
/**
|
||||
* 테이블 DDL 조회
|
||||
*/
|
||||
@PostMapping("/ddl.do")
|
||||
@ResponseBody
|
||||
public ResponseEntity<Map<String, String>> getTableDdl(HttpServletRequest request, @RequestBody SqlRequestDto sqlRequest) {
|
||||
checkAdminAccess(request);
|
||||
String ddl = dbConsoleService.getTableDdl(sqlRequest);
|
||||
Map<String, String> result = new HashMap<>();
|
||||
result.put("ddl", ddl);
|
||||
return ResponseEntity.ok(result);
|
||||
}
|
||||
|
||||
/**
|
||||
* 세션 하트비트 (커넥션 유지용)
|
||||
*/
|
||||
@PostMapping("/heartbeat.do")
|
||||
@ResponseBody
|
||||
public ResponseEntity<SqlResultDto> heartbeat(HttpServletRequest request, @RequestBody SqlRequestDto sqlRequest) {
|
||||
checkAdminAccess(request);
|
||||
SqlResultDto result = dbConsoleService.heartbeat(sqlRequest.getSessionId());
|
||||
// 남은 시간도 함께 반환
|
||||
long remainingSeconds = dbConsoleService.getSessionRemainingTime(sqlRequest.getSessionId());
|
||||
result.setMessage(result.getMessage() + " (남은시간: " + remainingSeconds + "초)");
|
||||
return ResponseEntity.ok(result);
|
||||
}
|
||||
|
||||
/**
|
||||
* SafeDB 암호화 데이터 복호화 (단일 값)
|
||||
*/
|
||||
@PostMapping("/decrypt.do")
|
||||
@ResponseBody
|
||||
public ResponseEntity<Map<String, Object>> decryptValue(HttpServletRequest request, @RequestBody Map<String, String> params) {
|
||||
checkAdminAccess(request);
|
||||
|
||||
String encryptedValue = params.get("value");
|
||||
if (encryptedValue == null || encryptedValue.isEmpty()) {
|
||||
Map<String, Object> result = new HashMap<>();
|
||||
result.put("success", false);
|
||||
result.put("message", "복호화할 값이 없습니다.");
|
||||
return ResponseEntity.ok(result);
|
||||
}
|
||||
|
||||
try {
|
||||
String decryptedValue = decryptService.decryptValue(encryptedValue);
|
||||
Map<String, Object> result = new HashMap<>();
|
||||
result.put("success", true);
|
||||
result.put("originalValue", encryptedValue);
|
||||
result.put("decryptedValue", decryptedValue);
|
||||
return ResponseEntity.ok(result);
|
||||
} catch (Exception e) {
|
||||
log.error("복호화 오류", e);
|
||||
Map<String, Object> result = new HashMap<>();
|
||||
result.put("success", false);
|
||||
result.put("message", "복호화 오류: " + e.getMessage());
|
||||
return ResponseEntity.ok(result);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* SafeDB 암호화 데이터 복호화 (여러 값)
|
||||
*/
|
||||
@PostMapping("/decryptBatch.do")
|
||||
@ResponseBody
|
||||
public ResponseEntity<Map<String, Object>> decryptBatch(HttpServletRequest request, @RequestBody Map<String, List<String>> params) {
|
||||
checkAdminAccess(request);
|
||||
|
||||
List<String> encryptedValues = params.get("values");
|
||||
if (encryptedValues == null || encryptedValues.isEmpty()) {
|
||||
Map<String, Object> result = new HashMap<>();
|
||||
result.put("success", false);
|
||||
result.put("message", "복호화할 값이 없습니다.");
|
||||
return ResponseEntity.ok(result);
|
||||
}
|
||||
|
||||
try {
|
||||
Map<String, String> decryptedMap = decryptService.decryptValues(encryptedValues);
|
||||
Map<String, Object> result = new HashMap<>();
|
||||
result.put("success", true);
|
||||
result.put("decrypted", decryptedMap);
|
||||
return ResponseEntity.ok(result);
|
||||
} catch (Exception e) {
|
||||
log.error("복호화 오류", e);
|
||||
Map<String, Object> result = new HashMap<>();
|
||||
result.put("success", false);
|
||||
result.put("message", "복호화 오류: " + e.getMessage());
|
||||
return ResponseEntity.ok(result);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 값이 암호화되었는지 확인
|
||||
*/
|
||||
@PostMapping("/checkEncrypted.do")
|
||||
@ResponseBody
|
||||
public ResponseEntity<Map<String, Object>> checkEncrypted(HttpServletRequest request, @RequestBody Map<String, String> params) {
|
||||
checkAdminAccess(request);
|
||||
|
||||
String value = params.get("value");
|
||||
boolean isEncrypted = decryptService.isEncrypted(value);
|
||||
|
||||
Map<String, Object> result = new HashMap<>();
|
||||
result.put("success", true);
|
||||
result.put("value", value);
|
||||
result.put("isEncrypted", isEncrypted);
|
||||
return ResponseEntity.ok(result);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,81 @@
|
||||
package com.eactive.eai.rms.common.dbconsole.dto;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
/**
|
||||
* 컬럼 정보 DTO
|
||||
*/
|
||||
@Data
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class ColumnInfoDto {
|
||||
|
||||
/**
|
||||
* 컬럼명
|
||||
*/
|
||||
private String columnName;
|
||||
|
||||
/**
|
||||
* 데이터 타입
|
||||
*/
|
||||
private String dataType;
|
||||
|
||||
/**
|
||||
* 데이터 길이
|
||||
*/
|
||||
private Integer dataLength;
|
||||
|
||||
/**
|
||||
* NULL 허용 여부 (Y/N)
|
||||
*/
|
||||
private String nullable;
|
||||
|
||||
/**
|
||||
* 기본값
|
||||
*/
|
||||
private String defaultValue;
|
||||
|
||||
/**
|
||||
* 코멘트
|
||||
*/
|
||||
private String comments;
|
||||
|
||||
/**
|
||||
* 컬럼 순서
|
||||
*/
|
||||
private Integer columnId;
|
||||
|
||||
/**
|
||||
* PK 여부
|
||||
*/
|
||||
private boolean primaryKey;
|
||||
|
||||
/**
|
||||
* UK 여부
|
||||
*/
|
||||
private boolean uniqueKey;
|
||||
|
||||
/**
|
||||
* FK 여부
|
||||
*/
|
||||
private boolean foreignKey;
|
||||
|
||||
/**
|
||||
* 인덱스 여부
|
||||
*/
|
||||
private boolean indexed;
|
||||
|
||||
/**
|
||||
* 인덱스명 (콤마로 구분)
|
||||
*/
|
||||
private String indexName;
|
||||
|
||||
/**
|
||||
* LOB 타입 여부
|
||||
*/
|
||||
private boolean lobType;
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
package com.eactive.eai.rms.common.dbconsole.dto;
|
||||
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* 데이터소스 정보 DTO
|
||||
*/
|
||||
@Data
|
||||
@Builder
|
||||
public class DatasourceInfoDto {
|
||||
|
||||
/**
|
||||
* 표시 이름
|
||||
*/
|
||||
private String displayName;
|
||||
|
||||
/**
|
||||
* 타입 (JNDI, DIRECT)
|
||||
*/
|
||||
private String type;
|
||||
|
||||
/**
|
||||
* 설명
|
||||
*/
|
||||
private String description;
|
||||
|
||||
/**
|
||||
* JNDI 이름
|
||||
*/
|
||||
private String jndiName;
|
||||
|
||||
/**
|
||||
* JDBC URL
|
||||
*/
|
||||
private String jdbcUrl;
|
||||
|
||||
/**
|
||||
* 사용자명
|
||||
*/
|
||||
private String username;
|
||||
|
||||
/**
|
||||
* 드라이버 클래스명
|
||||
*/
|
||||
private String driverClassName;
|
||||
|
||||
/**
|
||||
* 스키마명
|
||||
*/
|
||||
private String schema;
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
package com.eactive.eai.rms.common.dbconsole.dto;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* SQL 실행 요청 DTO
|
||||
*/
|
||||
@Data
|
||||
public class SqlRequestDto {
|
||||
|
||||
/**
|
||||
* 세션 ID
|
||||
*/
|
||||
private String sessionId;
|
||||
|
||||
/**
|
||||
* 실행할 SQL
|
||||
*/
|
||||
private String sql;
|
||||
|
||||
/**
|
||||
* 액션 (EXECUTE, COMMIT, ROLLBACK, DISCONNECT)
|
||||
*/
|
||||
private String action;
|
||||
|
||||
/**
|
||||
* 최대 조회 행 수
|
||||
*/
|
||||
private Integer maxRows;
|
||||
|
||||
/**
|
||||
* 데이터소스 타입 (JNDI, DIRECT)
|
||||
*/
|
||||
private String datasourceType;
|
||||
|
||||
/**
|
||||
* JNDI 이름
|
||||
*/
|
||||
private String jndiName;
|
||||
|
||||
/**
|
||||
* JDBC URL (DIRECT 연결 시)
|
||||
*/
|
||||
private String jdbcUrl;
|
||||
|
||||
/**
|
||||
* 사용자명 (DIRECT 연결 시)
|
||||
*/
|
||||
private String username;
|
||||
|
||||
/**
|
||||
* 비밀번호 (DIRECT 연결 시 또는 COMMIT 확인용)
|
||||
*/
|
||||
private String password;
|
||||
|
||||
/**
|
||||
* 드라이버 클래스명
|
||||
*/
|
||||
private String driverClassName;
|
||||
|
||||
/**
|
||||
* 스키마명 (테이블/컬럼 조회 시)
|
||||
*/
|
||||
private String schemaName;
|
||||
|
||||
/**
|
||||
* 테이블명 (컬럼/DDL 조회 시)
|
||||
*/
|
||||
private String tableName;
|
||||
}
|
||||
@@ -0,0 +1,83 @@
|
||||
package com.eactive.eai.rms.common.dbconsole.dto;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* SQL 실행 결과 DTO
|
||||
*/
|
||||
@Data
|
||||
public class SqlResultDto {
|
||||
|
||||
/**
|
||||
* 성공 여부
|
||||
*/
|
||||
private boolean success;
|
||||
|
||||
/**
|
||||
* 메시지
|
||||
*/
|
||||
private String message;
|
||||
|
||||
/**
|
||||
* 세션 ID
|
||||
*/
|
||||
private String sessionId;
|
||||
|
||||
/**
|
||||
* 쿼리 타입 (SELECT, INSERT, UPDATE, DELETE, DDL, ERROR, MULTI)
|
||||
*/
|
||||
private String queryType;
|
||||
|
||||
/**
|
||||
* 컬럼 목록 (SELECT 결과)
|
||||
*/
|
||||
private List<String> columns;
|
||||
|
||||
/**
|
||||
* 컬럼 메타정보 (SELECT 결과)
|
||||
*/
|
||||
private List<ColumnInfoDto> columnMetas;
|
||||
|
||||
/**
|
||||
* 데이터 행 (SELECT 결과)
|
||||
*/
|
||||
private List<Map<String, Object>> rows;
|
||||
|
||||
/**
|
||||
* 영향받은 행 수 (INSERT, UPDATE, DELETE)
|
||||
*/
|
||||
private Integer affectedRows;
|
||||
|
||||
/**
|
||||
* 실행 시간 (ms)
|
||||
*/
|
||||
private Long executionTime;
|
||||
|
||||
/**
|
||||
* 트랜잭션 활성 상태
|
||||
*/
|
||||
private boolean transactionActive;
|
||||
|
||||
/**
|
||||
* 성공 결과 생성
|
||||
*/
|
||||
public static SqlResultDto success(String message) {
|
||||
SqlResultDto result = new SqlResultDto();
|
||||
result.setSuccess(true);
|
||||
result.setMessage(message);
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* 오류 결과 생성
|
||||
*/
|
||||
public static SqlResultDto error(String message) {
|
||||
SqlResultDto result = new SqlResultDto();
|
||||
result.setSuccess(false);
|
||||
result.setMessage(message);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
package com.eactive.eai.rms.common.dbconsole.dto;
|
||||
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* 테이블 정보 DTO
|
||||
*/
|
||||
@Data
|
||||
@Builder
|
||||
public class TableInfoDto {
|
||||
|
||||
/**
|
||||
* 테이블명
|
||||
*/
|
||||
private String tableName;
|
||||
|
||||
/**
|
||||
* 테이블 타입 (TABLE, VIEW)
|
||||
*/
|
||||
private String tableType;
|
||||
|
||||
/**
|
||||
* 코멘트
|
||||
*/
|
||||
private String comments;
|
||||
}
|
||||
+139
@@ -0,0 +1,139 @@
|
||||
package com.eactive.eai.rms.common.dbconsole.service;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import com.eactive.ext.kjb.safedb.KjbSafedbWrapper;
|
||||
|
||||
/**
|
||||
* DB Console 복호화 서비스
|
||||
* - SafeDB 암호화 데이터 복호화 기능 제공
|
||||
*/
|
||||
@Service
|
||||
public class DbConsoleDecryptService {
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger(DbConsoleDecryptService.class);
|
||||
|
||||
/**
|
||||
* SafeDB 암호화 패턴 (16진수 문자열, 최소 32자 이상)
|
||||
* - 암호화된 데이터는 대체로 긴 16진수 문자열 형태
|
||||
*/
|
||||
private static final Pattern ENCRYPTED_PATTERN = Pattern.compile("^[0-9A-Fa-f]{32,}$");
|
||||
|
||||
/**
|
||||
* 단일 값 복호화
|
||||
*/
|
||||
public String decryptValue(String encryptedValue) {
|
||||
if (encryptedValue == null || encryptedValue.isEmpty()) {
|
||||
return encryptedValue;
|
||||
}
|
||||
|
||||
try {
|
||||
KjbSafedbWrapper safedb = KjbSafedbWrapper.getInstance();
|
||||
String decrypted = safedb.decryptNotRnno(encryptedValue);
|
||||
log.debug("복호화 성공: {} -> {}",
|
||||
encryptedValue.length() > 20 ? encryptedValue.substring(0, 20) + "..." : encryptedValue,
|
||||
decrypted);
|
||||
return decrypted;
|
||||
} catch (Exception e) {
|
||||
log.warn("복호화 실패: {}", e.getMessage());
|
||||
return "[복호화 실패: " + e.getMessage() + "]";
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 여러 값 일괄 복호화
|
||||
*/
|
||||
public Map<String, String> decryptValues(List<String> encryptedValues) {
|
||||
Map<String, String> result = new HashMap<>();
|
||||
|
||||
if (encryptedValues == null || encryptedValues.isEmpty()) {
|
||||
return result;
|
||||
}
|
||||
|
||||
for (String encrypted : encryptedValues) {
|
||||
if (encrypted != null && !encrypted.isEmpty()) {
|
||||
result.put(encrypted, decryptValue(encrypted));
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* 행 데이터에서 암호화 컬럼 복호화
|
||||
* @param rows 원본 행 데이터
|
||||
* @param columns 복호화할 컬럼명 목록
|
||||
* @return 복호화된 행 데이터
|
||||
*/
|
||||
public List<Map<String, Object>> decryptRows(List<Map<String, Object>> rows, List<String> columns) {
|
||||
if (rows == null || rows.isEmpty() || columns == null || columns.isEmpty()) {
|
||||
return rows;
|
||||
}
|
||||
|
||||
List<Map<String, Object>> decryptedRows = new ArrayList<>();
|
||||
|
||||
for (Map<String, Object> row : rows) {
|
||||
Map<String, Object> decryptedRow = new HashMap<>(row);
|
||||
|
||||
for (String column : columns) {
|
||||
Object value = row.get(column);
|
||||
if (value != null && value instanceof String) {
|
||||
String strValue = (String) value;
|
||||
if (isEncrypted(strValue)) {
|
||||
decryptedRow.put(column, decryptValue(strValue));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
decryptedRows.add(decryptedRow);
|
||||
}
|
||||
|
||||
return decryptedRows;
|
||||
}
|
||||
|
||||
/**
|
||||
* 값이 암호화된 것인지 확인 (휴리스틱)
|
||||
* - 16진수 문자열 패턴 (32자 이상)
|
||||
*/
|
||||
public boolean isEncrypted(String value) {
|
||||
if (value == null || value.length() < 32) {
|
||||
return false;
|
||||
}
|
||||
return ENCRYPTED_PATTERN.matcher(value).matches();
|
||||
}
|
||||
|
||||
/**
|
||||
* 컬럼별로 암호화 여부 자동 감지
|
||||
* @param rows 조회 결과 행
|
||||
* @return 암호화된 것으로 추정되는 컬럼명 목록
|
||||
*/
|
||||
public List<String> detectEncryptedColumns(List<Map<String, Object>> rows) {
|
||||
List<String> encryptedColumns = new ArrayList<>();
|
||||
|
||||
if (rows == null || rows.isEmpty()) {
|
||||
return encryptedColumns;
|
||||
}
|
||||
|
||||
// 첫 번째 행 기준으로 검사 (모든 행을 검사하면 비용이 높음)
|
||||
Map<String, Object> firstRow = rows.get(0);
|
||||
|
||||
for (Map.Entry<String, Object> entry : firstRow.entrySet()) {
|
||||
Object value = entry.getValue();
|
||||
if (value != null && value instanceof String) {
|
||||
if (isEncrypted((String) value)) {
|
||||
encryptedColumns.add(entry.getKey());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return encryptedColumns;
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -90,7 +90,7 @@ public class MenuService extends AbstractEMSDataSerivce<Menu, String, MenuReposi
|
||||
.where( qUserRole.id.userId.eq(userId),
|
||||
qMenu.menuUrl.like(url.concat("%")), qRole.useYn.eq("Y"),
|
||||
qRoleMenuAuth.auth.in("R", "W"),
|
||||
qRoleMenuAuth.id.serviceType.eq(serviceType)
|
||||
serviceType != null ? qRoleMenuAuth.id.serviceType.eq(serviceType) : qRoleMenuAuth.id.serviceType.isNull()
|
||||
)
|
||||
.setHint(QueryHints.CACHEABLE, true)
|
||||
.fetchOne();
|
||||
|
||||
Reference in New Issue
Block a user