韩国实名认证 (手机号+身份证实名认证)niceApi

admin 2708 2025-07-11 14:12:07

这是一个实名认证的对接api,是nice提供的,因为国内社区并不多,把自己对接国外实名认证的实现分享给社区,简单记录一下。 韩国大概是这样子的一个认证方式

然后我这里给一下官网的文档(我有翻译好的)https://www.niceapi.co.kr/#/apis/guide?ctgrCd=0100&prdId=31&prdNm=%EB%B3%B8%EC%9D%B8%ED%99%95%EC%9D%B8%28%ED%86%B5%ED%95%A9%ED%98%95%29

直接上代码吧,以上的秘钥都是处理了的,实际根据自己申请的为准

@RestController

@RequestMapping("/niceApi")

@Api(tags = "NICE API实名认证相关api")

@Slf4j

public class NiceAPIController extends BaseController {

@Autowired

private RedisCache redisCache;

private static final Logger logger = LoggerFactory.getLogger(FaceBookLoginController.class);

private static final String clientId = "1b9dd185-f0cb-212133-b6f22283d2269ff6";

private static final String clientSecret = "d4d1012646242121e7a1bd515e7e71ea6f12";

private static final String accessToken = "6f90befd-2aa9-41212-1c837740c41";

//获取全局token的url

private static final String niceApiGetAccessTokenUrl = "https://svc.niceapi.co.kr:22001/digital/niceid/oauth/oauth/token";

private static final String requestCryptoUrl = "https://svc.niceapi.co.kr:22001/digital/niceid/api/v1.0/common/crypto/token"; // API请求URL

private static final Integer productId = 2101979031;

/**

* nice获取全局token

*

* @return

*/

@PostMapping("/accessToken")

public static AjaxResult accessTokenTwo(){

// 构建请求URL和连接对象

HttpURLConnection connection = null;

try {

URL url = new URL(niceApiGetAccessTokenUrl);

connection = (HttpURLConnection) url.openConnection();

// 设置请求方法为POST

connection.setRequestMethod("POST");

// 设置请求头信息

connection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded;charset=utf-8");

// 构建授权信息

String credentials = clientId + ":" + clientSecret;

String encodedCredentials = Base64.getEncoder().encodeToString(credentials.getBytes(StandardCharsets.UTF_8));

connection.setRequestProperty("Authorization", "Basic " + encodedCredentials);

// 构建POST数据

String postData = "grant_type=client_credentials&scope=default";

// 发送请求

connection.setDoOutput(true);

try (OutputStream outputStream = connection.getOutputStream()) {

byte[] postDataBytes = postData.getBytes(StandardCharsets.UTF_8);

outputStream.write(postDataBytes);

outputStream.flush();

}

// 获取响应

int responseCode = connection.getResponseCode();

String responseData;

if (responseCode >= 200 && responseCode < 300) {

// 读取响应数据

BufferedReader reader = new BufferedReader(new InputStreamReader(connection.getInputStream()));

StringBuilder response = new StringBuilder();

String line;

while ((line = reader.readLine()) != null) {

response.append(line);

}

reader.close();

// 处理响应数据

responseData = response.toString();

} else {

// 读取错误响应数据

BufferedReader errorReader = new BufferedReader(new InputStreamReader(connection.getErrorStream()));

StringBuilder errorResponse = new StringBuilder();

String errorLine;

while ((errorLine = errorReader.readLine()) != null) {

errorResponse.append(errorLine);

}

errorReader.close();

// 处理错误响应数据

responseData = errorResponse.toString();

}

return new AjaxResult(responseCode, responseData);

} catch (IOException e) {

e.printStackTrace();

} finally {

if (connection != null) {

connection.disconnect();

}

}

return new AjaxResult(500, "操作失败");

}

/**

* 获取token加密请求

*

* @param

* @return

*/

public static String getTokenCrypto(String req_dtim, String req_no) {

String token = generateToken();

String requestPayload = "{\n" +

" \"dataHeader\": {\n" +

" \"CNTY_CD\": \"ko\"\n" +

" },\n" +

" \"dataBody\": {\n" +

" \"req_dtim\": \"" + req_dtim + "\",\n" +

" \"req_no\": \"" + req_no + "\",\n" +

" \"enc_mode\": \"1\"\n" +

" }\n" +

"}";

try {

URL url = new URL(requestCryptoUrl);

HttpURLConnection conn = (HttpURLConnection) url.openConnection();

conn.setRequestMethod("POST");

conn.setRequestProperty("Content-Type", "application/json");

conn.setRequestProperty("Authorization", "bearer " + token);

conn.setRequestProperty("ProductID", productId.toString());

conn.setDoOutput(true);

OutputStream os = conn.getOutputStream();

os.write(requestPayload.getBytes(StandardCharsets.UTF_8));

os.flush();

if (conn.getResponseCode() == HttpURLConnection.HTTP_OK) {

BufferedReader br = new BufferedReader(new InputStreamReader(conn.getInputStream()));

String responseLine;

StringBuilder responseBuilder = new StringBuilder();

while ((responseLine = br.readLine()) != null) {

responseBuilder.append(responseLine.trim());

}

br.close();

String response = responseBuilder.toString();

conn.disconnect();

return response;

} else {

System.out.println("API请求失败,响应码:" + conn.getResponseCode());

conn.disconnect();

return null;

}

} catch (Exception e) {

e.printStackTrace();

}

return null;

}

/**

* token加密请求 "bearer " + Base64Encoding(access_token:current_timestamp:client_id")

*

* @return

*/

private static String generateToken() {

// 计算当前时间戳

Date currentDate = new Date();

long current_timestamp = currentDate.getTime() / 1000;

// 构造token字符串

String tokenString = accessToken + ":" + current_timestamp + ":" + clientId;

// 对token进行Base64编码

byte[] tokenBytes = tokenString.getBytes(StandardCharsets.UTF_8);

String encodedToken = Base64.getEncoder().encodeToString(tokenBytes);

return encodedToken;

}

/**

* 创建密钥对 key vi hmac_key resultVal

*

* @param

* @throws NoSuchAlgorithmException

*/

public static KeyViEntity creatKeyAndVi(String req_dtim, String req_no, String token_val) throws NoSuchAlgorithmException {

KeyViEntity keyViEntity = new KeyViEntity();

// 获取"token加密请求"API请求和响应值,此处仅作示例,实际情况应根据API的实际返回值来获取req_dtim、req_no和token_val的值

// 生成对称密钥

String resultVal = generateHmacKey(req_dtim, req_no, token_val);

System.out.println("resultVal:" + resultVal);

//获取密钥对key vi

// 截取前16位

String key = resultVal.substring(0, 16);

System.out.println("前16位:" + key);

keyViEntity.setKey(key);

// 截取前32位

String hmac_key = resultVal.substring(0, 32);

System.out.println("前32位:" + hmac_key);

keyViEntity.setHmacKey(hmac_key);

// 截取后六位

String vi = resultVal.substring(resultVal.length() - 16);

System.out.println("后16位:" + vi);

keyViEntity.setVi(vi);

return keyViEntity;

}

/**

* 实名认证跳转接口

*

*/

@GetMapping(value = "/getNiceApiUrl")

public String getNiceApiUrl(NiceApiDTO niceApiDTO) throws NoSuchAlgorithmException {

// 获取当前时间的LocalDateTime对象

LocalDateTime now = LocalDateTime.now();

// 创建DateTimeFormatter对象,使用指定的格式

DateTimeFormatter formatter = DateTimeFormatter.ofPattern("uuuuMMddHHmmss");

// 使用DateTimeFormatter对象对LocalDateTime对象进行格式化

String formattedDateTime = now.format(formatter);

// 去除格式化后字符串中的非数字字符,得到"20230725162601"格式

String reqDtim = formattedDateTime.replaceAll("\\D", "");

System.out.println(reqDtim);

String reqNo = String.valueOf(System.currentTimeMillis());

System.out.println(reqNo);

//2.token加密请求

String tokenCrypto = getTokenCrypto(reqDtim, reqNo);

//解析token加密请求的返回结果

// 使用Gson库解析JSON字符串为Map

Gson gson = new Gson();

Map jsonDataMap = gson.fromJson(tokenCrypto, Map.class);

Map dataBodyMap =null;

// 检查GW_RSLT_CD是否等于"1200"

Map dataHeaderMap = (Map) jsonDataMap.get("dataHeader");

String gwRsltCd = (String) dataHeaderMap.get("GW_RSLT_CD");

if ("1200".equals(gwRsltCd)) {

// 如果GW_RSLT_CD等于"1200",则获取dataBody部分并转换为Map

dataBodyMap = (Map) jsonDataMap.get("dataBody");

System.out.println("dataBody转换为Map:" + dataBodyMap);

} else {

System.out.println("GW_RSLT_CD不等于1200,无法转换dataBody为Map。");

}

//3.获取token加密请求得到的token_version_id site_code token_val

String tokenVersionId = dataBodyMap.get("token_version_id").toString();

String siteCode = dataBodyMap.get("site_code").toString();

String tokenVal = dataBodyMap.get("token_val").toString();

//4.创建对称密钥 得到密钥对

KeyViEntity keyViEntity = creatKeyAndVi(reqDtim, reqNo, tokenVal);

String key=keyViEntity.getKey();

String hmacKey = keyViEntity.getHmacKey();

String iv = keyViEntity.getVi();

//5.加密数据请求

String requestNo = niceApiDTO.getSuperUserId();

NiceKeyAndVI niceKeyAndVI = new NiceKeyAndVI();

niceKeyAndVI.setKey(key);

niceKeyAndVI.setVi(iv);

redisCache.setCacheObject("niceAPI:"+niceApiDTO.getGameId()+":"+niceApiDTO.getSuperUserId(),niceKeyAndVI);

/* String s = MD5Utils.MD5(userId);*/

String returnUrl = "https://q33.com/isCardReal?superUserId="+niceApiDTO.getSuperUserId()+"&gameId="+niceApiDTO.getGameId()+"&userId="+niceApiDTO.getUserId();

logger.info("[returnUrl] ======> " + returnUrl);

String authType = "M";

String mobileEco = "S";

String businessNo = "xxxxdddeee";

String methodType = "get";

String popupYn = "Y";

String receiveData = "xxxxdddeee";

String jsonData = createRequestData(requestNo, returnUrl, siteCode, authType, mobileEco, businessNo, methodType, popupYn, receiveData);

System.out.println("请求数据(reqData)的JSON构成:\n" + jsonData);

String encryptedData = encryptRequestData(jsonData, key, iv);

System.out.println("JSON形态的请求数据加密:\n" + encryptedData);

String integrityValue = generateHmacIntegrityValue(encryptedData, hmacKey);

System.out.println("生成Hmac完整校验值(integrity_value):\n" + integrityValue);

//转义

integrityValue=integrityValue.replace("+","%2B");

String niceApi ="https://nice.checkplus.co.kr/CheckPlusSafeModel/service.cb";

String lastUrl =niceApi+"?"+"m=service"+"&token_version_id="+tokenVersionId+"&enc_data="+encryptedData+"&integrity_value="+integrityValue;

logger.info("[access_token] ======> " + lastUrl);

return lastUrl;

}

public static void main(String[] args) throws NoSuchAlgorithmException {

// 获取当前时间的LocalDateTime对象

LocalDateTime now = LocalDateTime.now();

// 创建DateTimeFormatter对象,使用指定的格式

DateTimeFormatter formatter = DateTimeFormatter.ofPattern("uuuuMMddHHmmss");

// 使用DateTimeFormatter对象对LocalDateTime对象进行格式化

String formattedDateTime = now.format(formatter);

// 去除格式化后字符串中的非数字字符,得到"20230725162601"格式

String reqDtim = formattedDateTime.replaceAll("\\D", "");

System.out.println(reqDtim);

String reqNo = String.valueOf(System.currentTimeMillis());

System.out.println(reqNo);

//2.token加密请求

String tokenCrypto = getTokenCrypto(reqDtim, reqNo);

//解析token加密请求的返回结果

// 使用Gson库解析JSON字符串为Map

Gson gson = new Gson();

Map jsonDataMap = gson.fromJson(tokenCrypto, Map.class);

Map dataBodyMap =null;

// 检查GW_RSLT_CD是否等于"1200"

Map dataHeaderMap = (Map) jsonDataMap.get("dataHeader");

String gwRsltCd = (String) dataHeaderMap.get("GW_RSLT_CD");

if ("1200".equals(gwRsltCd)) {

// 如果GW_RSLT_CD等于"1200",则获取dataBody部分并转换为Map

dataBodyMap = (Map) jsonDataMap.get("dataBody");

System.out.println("dataBody转换为Map:" + dataBodyMap);

} else {

System.out.println("GW_RSLT_CD不等于1200,无法转换dataBody为Map。");

}

//3.获取token加密请求得到的token_version_id site_code token_val

String tokenVersionId = dataBodyMap.get("token_version_id").toString();

String siteCode = dataBodyMap.get("site_code").toString();

String tokenVal = dataBodyMap.get("token_val").toString();

//4.创建对称密钥 得到密钥对

KeyViEntity keyViEntity = creatKeyAndVi(reqDtim, reqNo, tokenVal);

String key=keyViEntity.getKey();

String hmacKey = keyViEntity.getHmacKey();

String iv = keyViEntity.getVi();

/* String tokenVersionId="20230727130110GF-NC49CB567-2B1HD-219H5H84A8";

String siteCode="Q0I1Njc=";

String key="euAKqLokm8nOajen";

String hmacKey="euAKqLokm8nOajenHqhlvKxQVmo9Q8W5";

String iv="Q8W55Mj7LrJjW6M=";*/

//5.加密数据请求

String requestNo = "REQ2021123199";

String returnUrl = "https://e.com/自己的网站";

String authType = "M";

String mobileEco = "S";

String businessNo = "xxxxdddeee";

String methodType = "get";

String popupYn = "Y";

String receiveData = "xxxxdddeee";

String jsonData = createRequestData(requestNo, returnUrl, siteCode, authType, mobileEco, businessNo, methodType, popupYn, receiveData);

System.out.println("请求数据(reqData)的JSON构成:\n" + jsonData);

String encryptedData = encryptRequestData(jsonData, key, iv);

System.out.println("JSON形态的请求数据加密:\n" + encryptedData);

String integrityValue = generateHmacIntegrityValue(encryptedData, hmacKey);

System.out.println("生成Hmac完整校验值(integrity_value):\n" + integrityValue);

String niceApi ="https://nice.checkplus.co.kr/CheckPlusSafeModel/service.cb";

String lastUrl =niceApi+"?"+"m=service"+"&token_version_id="+tokenVersionId+"&enc_data="+encryptedData+"&integrity_value="+integrityValue;

System.out.println(lastUrl);

}

// 请求数据加密

public static String encryptRequestData(String reqData, String key, String iv) {

try {

SecretKeySpec secureKey = new SecretKeySpec(key.getBytes(), "AES");

Cipher c = Cipher.getInstance("AES/CBC/PKCS5Padding");

c.init(Cipher.ENCRYPT_MODE, secureKey, new IvParameterSpec(iv.getBytes()));

byte[] encrypted = c.doFinal(reqData.trim().getBytes());

return Base64.getEncoder().encodeToString(encrypted);

} catch (Exception e) {

e.printStackTrace();

return null;

}

}

// 生成Hmac完整校验值

public static String generateHmacIntegrityValue(String encData, String hmacKey) {

try {

Mac mac = Mac.getInstance("HmacSHA256");

SecretKeySpec sks = new SecretKeySpec(hmacKey.getBytes(), "HmacSHA256");

mac.init(sks);

byte[] hmacSha256 = mac.doFinal(encData.getBytes());

return Base64.getEncoder().encodeToString(hmacSha256);

} catch (Exception e) {

e.printStackTrace();

return null;

}

}

// 封装请求数据为JSON格式

public static String createRequestData(String requestNo, String returnUrl, String siteCode, String authType,

String mobileEco, String businessNo, String methodType, String popupYn,

String receiveData) {

StringBuilder jsonBuilder = new StringBuilder();

jsonBuilder.append("{")

.append("\"requestno\":\"").append(requestNo).append("\",")

.append("\"returnurl\":\"").append(returnUrl).append("\",")

.append("\"sitecode\":\"").append(siteCode).append("\",")

.append("\"authtype\":\"").append("M").append("\"")

.append("}");

return jsonBuilder.toString();

}

private static String generateHmacKey(String req_dtim, String req_no, String token_val) throws NoSuchAlgorithmException {

String value = req_dtim.trim() + req_no.trim() + token_val.trim();

MessageDigest md = MessageDigest.getInstance("SHA-256");

md.update(value.getBytes());

byte[] arrHashValue = md.digest();

return Base64.getEncoder().encodeToString(arrHashValue);

}

}

上一篇
下一篇
相关文章