parent
1b55a58e39
commit
c6a3166183
@ -0,0 +1,24 @@
|
|||||||
|
package kr.xit.ens.support.nice.service;
|
||||||
|
|
||||||
|
import kr.xit.biz.ens.model.nice.NiceCiDTO.TokenRequest;
|
||||||
|
import kr.xit.biz.ens.model.nice.NiceCiDTO.TokenResponse;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <pre>
|
||||||
|
* description :
|
||||||
|
*
|
||||||
|
* packageName : kr.xit.ens.support.nice.service
|
||||||
|
* fileName : INiceCiService
|
||||||
|
* author : limju
|
||||||
|
* date : 2023-09-06
|
||||||
|
* ======================================================================
|
||||||
|
* 변경일 변경자 변경 내용
|
||||||
|
* ----------------------------------------------------------------------
|
||||||
|
* 2023-09-06 limju 최초 생성
|
||||||
|
*
|
||||||
|
* </pre>
|
||||||
|
*/
|
||||||
|
public interface INiceCiService {
|
||||||
|
TokenResponse generateToken(final TokenRequest reqDTO);
|
||||||
|
TokenResponse revokeToken(final String token);
|
||||||
|
}
|
@ -0,0 +1,84 @@
|
|||||||
|
package kr.xit.ens.support.nice.service;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||||
|
import com.fasterxml.jackson.core.type.TypeReference;
|
||||||
|
import java.nio.charset.Charset;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
import kr.xit.biz.ens.model.kakao.KkopayDocBulkDTO.BulkSendResponses;
|
||||||
|
import kr.xit.biz.ens.model.nice.NiceCiDTO.TokenRequest;
|
||||||
|
import kr.xit.biz.ens.model.nice.NiceCiDTO.TokenResponse;
|
||||||
|
import kr.xit.core.spring.util.ApiWebClientUtil;
|
||||||
|
import kr.xit.core.support.utils.JsonUtils;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import org.apache.logging.log4j.util.Base64Util;
|
||||||
|
import org.egovframe.rte.fdl.cmmn.EgovAbstractServiceImpl;
|
||||||
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
|
import org.springframework.http.HttpHeaders;
|
||||||
|
import org.springframework.http.HttpMethod;
|
||||||
|
import org.springframework.http.MediaType;
|
||||||
|
import org.springframework.http.ResponseEntity;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
import org.springframework.util.LinkedMultiValueMap;
|
||||||
|
import org.springframework.util.MultiValueMap;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <pre>
|
||||||
|
* description :
|
||||||
|
*
|
||||||
|
* packageName : kr.xit.ens.support.nice.service
|
||||||
|
* fileName : NiceCiService
|
||||||
|
* author : limju
|
||||||
|
* date : 2023-09-06
|
||||||
|
* ======================================================================
|
||||||
|
* 변경일 변경자 변경 내용
|
||||||
|
* ----------------------------------------------------------------------
|
||||||
|
* 2023-09-06 limju 최초 생성
|
||||||
|
*
|
||||||
|
* </pre>
|
||||||
|
*/
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
@Service
|
||||||
|
public class NiceCiService extends EgovAbstractServiceImpl implements INiceCiService {
|
||||||
|
@Value("${contract.nice.host}")
|
||||||
|
private String HOST;
|
||||||
|
@Value("${contract.nice.client-id}")
|
||||||
|
private String CLIENT_ID;
|
||||||
|
@Value("${contract.nice.client-secret}")
|
||||||
|
private String CLIENT_SECRET;
|
||||||
|
@Value("${contract.nice.api.generate-token}")
|
||||||
|
private String API_GENERATE_TOKEN;
|
||||||
|
@Value("${contract.nice.api.revoke-token}")
|
||||||
|
private String API_REVOKE_TOKEN;
|
||||||
|
@Value("${contract.nice.api.publickey}")
|
||||||
|
private String API_PUBLICKEY;
|
||||||
|
@Value("${contract.nice.api.symmetrickey}")
|
||||||
|
private String API_SYMMETRICKEY;
|
||||||
|
@Value("${contract.nice.api.ci}")
|
||||||
|
private String API_CI;
|
||||||
|
|
||||||
|
private final ApiWebClientUtil webClient;
|
||||||
|
|
||||||
|
public TokenResponse generateToken(final TokenRequest reqDTO){
|
||||||
|
return webClient.exchange(HOST + API_GENERATE_TOKEN, HttpMethod.POST, JsonUtils.toJson(reqDTO), TokenResponse.class, getHeaderMap());
|
||||||
|
}
|
||||||
|
|
||||||
|
public TokenResponse revokeToken(final String token){
|
||||||
|
Map<String,String> map = new HashMap<>();
|
||||||
|
map.put(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_FORM_URLENCODED_VALUE);
|
||||||
|
map.put(HttpHeaders.AUTHORIZATION, String.format("Basic %s", Base64Util.encode(String.format("%s:%s:%s", token, (new Date().getTime() / 1000), this.CLIENT_SECRET))));
|
||||||
|
return webClient.exchange(HOST + API_GENERATE_TOKEN, HttpMethod.POST, null, TokenResponse.class, getHeaderMap());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------
|
||||||
|
private Map<String,String> getHeaderMap(){
|
||||||
|
Map<String,String> map = new HashMap<>();
|
||||||
|
map.put(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_FORM_URLENCODED_VALUE);
|
||||||
|
map.put(HttpHeaders.AUTHORIZATION, String.format("Basic %s", Base64Util.encode(String.format("%s:%s", this.CLIENT_ID, this.CLIENT_SECRET))));
|
||||||
|
return map;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,54 @@
|
|||||||
|
package kr.xit.ens.support.nice.web;
|
||||||
|
|
||||||
|
import io.swagger.v3.oas.annotations.Operation;
|
||||||
|
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||||
|
import kr.xit.biz.ens.model.kakao.KkopayDocDTO.ValidTokenRequest;
|
||||||
|
import kr.xit.biz.ens.model.nice.NiceCiDTO.TokenRequest;
|
||||||
|
import kr.xit.core.model.ApiResponseDTO;
|
||||||
|
import kr.xit.ens.support.nice.service.INiceCiService;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import org.springframework.http.MediaType;
|
||||||
|
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.RequestParam;
|
||||||
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <pre>
|
||||||
|
* description :
|
||||||
|
*
|
||||||
|
* packageName : kr.xit.ens.support.nice.web
|
||||||
|
* fileName : NiceCiController
|
||||||
|
* author : limju
|
||||||
|
* date : 2023-09-06
|
||||||
|
* ======================================================================
|
||||||
|
* 변경일 변경자 변경 내용
|
||||||
|
* ----------------------------------------------------------------------
|
||||||
|
* 2023-09-06 limju 최초 생성
|
||||||
|
*
|
||||||
|
* </pre>
|
||||||
|
*/
|
||||||
|
@Tag(name = "NiceCiController", description = "Nice CI API")
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
@RestController
|
||||||
|
@RequestMapping(value = "/api/nice/v1")
|
||||||
|
public class NiceCiController {
|
||||||
|
private final INiceCiService service;
|
||||||
|
|
||||||
|
@Operation(summary = "기관용 토큰 발급 요청", description = "기관용 토큰 발급 요청")
|
||||||
|
@PostMapping(value = "/generateToken", produces = MediaType.APPLICATION_JSON_VALUE)
|
||||||
|
public ApiResponseDTO<?> generateToken(
|
||||||
|
@RequestBody final TokenRequest reqDTO
|
||||||
|
) {
|
||||||
|
return ApiResponseDTO.success(service.generateToken(reqDTO));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Operation(summary = "기관용 토큰 폐기", description = "기관용 토큰 폐기")
|
||||||
|
@PostMapping(value = "/revokeToken", produces = MediaType.APPLICATION_JSON_VALUE)
|
||||||
|
public ApiResponseDTO<?> revokeToken(
|
||||||
|
@RequestParam final String accessToken
|
||||||
|
) {
|
||||||
|
return ApiResponseDTO.success(service.revokeToken(accessToken));
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,205 @@
|
|||||||
|
package kr.xit.biz.ens.model.nice;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.annotation.JsonInclude;
|
||||||
|
import io.swagger.v3.oas.annotations.media.Schema;
|
||||||
|
import io.swagger.v3.oas.annotations.media.Schema.RequiredMode;
|
||||||
|
import java.util.List;
|
||||||
|
import javax.validation.Valid;
|
||||||
|
import javax.validation.constraints.Digits;
|
||||||
|
import javax.validation.constraints.NotBlank;
|
||||||
|
import javax.validation.constraints.NotNull;
|
||||||
|
import javax.validation.constraints.Size;
|
||||||
|
import kr.xit.biz.common.ApiConstants;
|
||||||
|
import kr.xit.core.model.IApiResponse;
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
import lombok.experimental.SuperBuilder;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <pre>
|
||||||
|
* description : Nice CI DTO
|
||||||
|
*
|
||||||
|
* packageName : kr.xit.biz.ens.model.nice
|
||||||
|
* fileName : NiceCiDTO
|
||||||
|
* author : limju
|
||||||
|
* date : 2023-09-06
|
||||||
|
* ======================================================================
|
||||||
|
* 변경일 변경자 변경 내용
|
||||||
|
* ----------------------------------------------------------------------
|
||||||
|
* 2023-09-06 limju 최초 생성
|
||||||
|
*
|
||||||
|
* </pre>
|
||||||
|
*/
|
||||||
|
public class NiceCiDTO {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <pre>
|
||||||
|
* 기관용 Token(50년 유효) 발급 요청
|
||||||
|
* url : /digital/niceid/oauth/oauth/token
|
||||||
|
* content-type : application/x-www-form-urlencoded
|
||||||
|
* Authorization : Basic + Base64Encoding(access_token:current_timestamp:client_id)
|
||||||
|
* - access_token : 만료할 access_token
|
||||||
|
* - client_id : access_token발급에 사용된 client_id
|
||||||
|
* - current_timestamp
|
||||||
|
* Date currentDate = new Date();
|
||||||
|
* long current_timestamp = currentDate.getTime() /1000
|
||||||
|
* </pre>
|
||||||
|
*/
|
||||||
|
@Schema(name = "Token", description = "기관용 Token(50년 유효) 발급 요청 파라메터 DTO")
|
||||||
|
@Data
|
||||||
|
@NoArgsConstructor
|
||||||
|
@AllArgsConstructor
|
||||||
|
@SuperBuilder
|
||||||
|
@JsonInclude(JsonInclude.Include.NON_NULL)
|
||||||
|
public static class TokenRequest {
|
||||||
|
/**
|
||||||
|
* default 로 고정
|
||||||
|
*/
|
||||||
|
@Schema(requiredMode = RequiredMode.REQUIRED, title = "scope", example = "default")
|
||||||
|
@NotBlank(message = "scope는 필수입니다")
|
||||||
|
private String scope;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* clinet_credentials 로 고정
|
||||||
|
*/
|
||||||
|
@Schema(requiredMode = RequiredMode.REQUIRED, title = "grant_type", example = "clinet_credentials")
|
||||||
|
@NotBlank(message = "grant_type은 필수입니다")
|
||||||
|
private String grant_type;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <pre>
|
||||||
|
* 기관용 Token(50년 유효) 발급 요청 응답
|
||||||
|
* url : /digital/niceid/oauth/oauth/token
|
||||||
|
* content-type : application/json
|
||||||
|
* </pre>
|
||||||
|
*/
|
||||||
|
@Schema(name = "TokenResponse", description = "기관용 Token(50년 유효) 발급 요청 결과 DTO")
|
||||||
|
@Data
|
||||||
|
@NoArgsConstructor
|
||||||
|
@AllArgsConstructor
|
||||||
|
@SuperBuilder
|
||||||
|
@JsonInclude(JsonInclude.Include.NON_NULL)
|
||||||
|
public static class TokenResponse implements IApiResponse {
|
||||||
|
@Schema(requiredMode = RequiredMode.REQUIRED)
|
||||||
|
private DataHeader dataHeader;
|
||||||
|
|
||||||
|
@Schema(requiredMode = RequiredMode.REQUIRED)
|
||||||
|
private DataBody dataBody;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <pre>
|
||||||
|
* 기관용 Token 폐기 응답
|
||||||
|
* 요청
|
||||||
|
* url : /digital/niceid/oauth/oauth/token/revokeById
|
||||||
|
* Authorization : Basic + Base64Encoding(access_token:current_timestamp:client_id)
|
||||||
|
* - access_token : 만료할 access_token
|
||||||
|
* - client_id : access_token발급에 사용된 client_id
|
||||||
|
* - current_timestamp
|
||||||
|
* Date currentDate = new Date();
|
||||||
|
* long current_timestamp = currentDate.getTime() /1000
|
||||||
|
* </pre>
|
||||||
|
*/
|
||||||
|
@Schema(name = "TokenRevokeResponse", description = "기관용 Token 폐기 요청 결과 DTO")
|
||||||
|
@Data
|
||||||
|
@NoArgsConstructor
|
||||||
|
@AllArgsConstructor
|
||||||
|
@SuperBuilder
|
||||||
|
@JsonInclude(JsonInclude.Include.NON_NULL)
|
||||||
|
public static class TokenRevokeResponse implements IApiResponse {
|
||||||
|
|
||||||
|
@Schema(requiredMode = RequiredMode.REQUIRED)
|
||||||
|
private DataHeader dataHeader;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 기관용 토큰 발급 응답 dataHeader
|
||||||
|
*/
|
||||||
|
@Schema(name = "DataHeader", description = "TokenResponse dataHeader DTO")
|
||||||
|
@Data
|
||||||
|
@NoArgsConstructor
|
||||||
|
@AllArgsConstructor
|
||||||
|
@SuperBuilder
|
||||||
|
@JsonInclude(JsonInclude.Include.NON_NULL)
|
||||||
|
public static class DataHeader {
|
||||||
|
/**
|
||||||
|
* 응답코드
|
||||||
|
* 정상 : 1200, 그외 오류
|
||||||
|
*/
|
||||||
|
@Schema(requiredMode = RequiredMode.REQUIRED, title = "응답코드", example = "1200")
|
||||||
|
@NotBlank
|
||||||
|
private String GW_RSLT_CD;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 응답메세지
|
||||||
|
*/
|
||||||
|
@Schema(requiredMode = RequiredMode.REQUIRED, title = "응답메세지", example = "오류없음")
|
||||||
|
@NotBlank
|
||||||
|
private String GW_RSLT_MSG;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* TRAN_ID
|
||||||
|
*/
|
||||||
|
@Schema(requiredMode = RequiredMode.AUTO, title = "TRAN_ID", example = "20230906120000")
|
||||||
|
private String TRAN_ID;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 기관용 토큰 발급 응답 dataHeader
|
||||||
|
*/
|
||||||
|
@Schema(name = "DataBody", description = "TokenResponse dataBody DTO")
|
||||||
|
@Data
|
||||||
|
@NoArgsConstructor
|
||||||
|
@AllArgsConstructor
|
||||||
|
@SuperBuilder
|
||||||
|
@JsonInclude(JsonInclude.Include.NON_NULL)
|
||||||
|
public static class DataBody {
|
||||||
|
//-----------------------------------------------------------------------
|
||||||
|
// 토근 발급 요청시 필수
|
||||||
|
//-----------------------------------------------------------------------
|
||||||
|
/**
|
||||||
|
* 사용자 엑세스 토큰 값 : token 발급시 필수
|
||||||
|
* 모든 API 요청시 헤더에 access_token을 포함하여 전송
|
||||||
|
*/
|
||||||
|
@Schema(requiredMode = RequiredMode.AUTO, title = "사용자 엑세스 토큰 값", example = " ")
|
||||||
|
@NotBlank
|
||||||
|
private String access_token;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* token_type : token 발급시 필수
|
||||||
|
* bearer로 고정
|
||||||
|
*/
|
||||||
|
@Schema(requiredMode = RequiredMode.AUTO, title = "token_type", example = "bearer")
|
||||||
|
@NotBlank
|
||||||
|
private String token_type;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* access 토큰 만료 시간(초) : token 발급시 필수
|
||||||
|
*/
|
||||||
|
@Schema(requiredMode = RequiredMode.AUTO, title = "access 토큰 만료 시간(초)", example = "1.57698305E9")
|
||||||
|
@NotBlank
|
||||||
|
private int expires_in;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 요청한 scope 값 : token 발급시 필수
|
||||||
|
* 기본 : default
|
||||||
|
*/
|
||||||
|
@Schema(requiredMode = RequiredMode.AUTO, title = "요청한 scope 값", example = "default")
|
||||||
|
@NotBlank
|
||||||
|
private String scope;
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------
|
||||||
|
// 토큰 폐기 요청시 필수
|
||||||
|
//-----------------------------------------------------------------------
|
||||||
|
/**
|
||||||
|
* token 폐기시 필수
|
||||||
|
* true or false
|
||||||
|
*/
|
||||||
|
@Schema(requiredMode = RequiredMode.AUTO)
|
||||||
|
@NotBlank
|
||||||
|
private boolean result;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,52 @@
|
|||||||
|
package kr.xit.core.support.utils;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.security.MessageDigest;
|
||||||
|
import java.security.NoSuchAlgorithmException;
|
||||||
|
import kr.xit.core.exception.BizRuntimeException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <pre>
|
||||||
|
* description :
|
||||||
|
*
|
||||||
|
* packageName : kr.xit.core.support.utils
|
||||||
|
* fileName : SecureUtils
|
||||||
|
* author : limju
|
||||||
|
* date : 2023-09-06
|
||||||
|
* ======================================================================
|
||||||
|
* 변경일 변경자 변경 내용
|
||||||
|
* ----------------------------------------------------------------------
|
||||||
|
* 2023-09-06 limju 최초 생성
|
||||||
|
*
|
||||||
|
* </pre>
|
||||||
|
*/
|
||||||
|
public class SecureUtils {
|
||||||
|
/**
|
||||||
|
* sha256 암호화
|
||||||
|
*
|
||||||
|
* @param text
|
||||||
|
* @return
|
||||||
|
* @throws IOException
|
||||||
|
* @throws NoSuchAlgorithmException
|
||||||
|
*/
|
||||||
|
public static String hexSha256(String text) {
|
||||||
|
StringBuffer sbuf = new StringBuffer();
|
||||||
|
|
||||||
|
try {
|
||||||
|
MessageDigest mDigest = MessageDigest.getInstance("SHA-256");
|
||||||
|
mDigest.update(text.getBytes());
|
||||||
|
|
||||||
|
byte[] msgStr = mDigest.digest();
|
||||||
|
|
||||||
|
for(int i = 0; i < msgStr.length; i++) {
|
||||||
|
byte tmpStrByte = msgStr[i];
|
||||||
|
String tmpEncTxt = Integer.toString((tmpStrByte & 0xff) + 0x100, 16).substring(1);
|
||||||
|
|
||||||
|
sbuf.append(tmpEncTxt);
|
||||||
|
}
|
||||||
|
} catch (NoSuchAlgorithmException nae){
|
||||||
|
throw BizRuntimeException.create(nae.getMessage());
|
||||||
|
}
|
||||||
|
return sbuf.toString();
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue