|
@@ -0,0 +1,330 @@
|
|
|
+package com.ruoyi.web.controller.Idcard;
|
|
|
+
|
|
|
+/**
|
|
|
+ * @Author: tjf
|
|
|
+ * @Date: 2024/4/17 9:35
|
|
|
+ * @Describe:
|
|
|
+ */
|
|
|
+
|
|
|
+import com.alibaba.fastjson2.JSON;
|
|
|
+import com.alibaba.fastjson2.JSONObject;
|
|
|
+import com.ruoyi.common.utils.FileUtil;
|
|
|
+import com.ruoyi.common.utils.HttpUtil;
|
|
|
+import okhttp3.*;
|
|
|
+
|
|
|
+import javax.crypto.Cipher;
|
|
|
+import javax.crypto.spec.SecretKeySpec;
|
|
|
+import java.io.IOException;
|
|
|
+import java.net.URLEncoder;
|
|
|
+import java.util.Base64;
|
|
|
+
|
|
|
+public class Idcard {
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 重要提示代码中所需工具类
|
|
|
+ * FileUtil,HttpUtil请从
|
|
|
+ * https://ai.baidu.com/file/658A35ABAB2D404FBF903F64D47C1F72
|
|
|
+ * https://ai.baidu.com/file/544D677F5D4E4F17B4122FBD60DB82B3
|
|
|
+ * 下载
|
|
|
+ * <p>
|
|
|
+ * https://cloud.baidu.com/doc/OCR/s/rk3h7xzck 文档地址
|
|
|
+ */
|
|
|
+
|
|
|
+ // 请求url
|
|
|
+ static String url = "https://aip.baidubce.com/rest/2.0/ocr/v1/idcard";
|
|
|
+
|
|
|
+ // aes key 从console控制台获取
|
|
|
+ static String aesKey = "[16位 aeskey]";
|
|
|
+
|
|
|
+ static byte[] originAesKey = null;
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 身份证识别
|
|
|
+ * {
|
|
|
+ * "log_id": "1559208562721579319",
|
|
|
+ * "direction": 0,
|
|
|
+ * "image_status": "normal",
|
|
|
+ * "photo": "/9j/4AAQSkZJRgABA......",
|
|
|
+ * "photo_location": {
|
|
|
+ * "width": 1189,
|
|
|
+ * "top": 638,
|
|
|
+ * "left": 2248,
|
|
|
+ * "height": 1483
|
|
|
+ * },
|
|
|
+ * "card_image": "/9j/4AAQSkZJRgABA......",
|
|
|
+ * "card_location": {
|
|
|
+ * "top": 328,
|
|
|
+ * "left": 275,
|
|
|
+ * "width": 1329,
|
|
|
+ * "height": 571
|
|
|
+ * },
|
|
|
+ * "words_result": {
|
|
|
+ * "住址": {
|
|
|
+ * "location": {
|
|
|
+ * "left": 267,
|
|
|
+ * "top": 453,
|
|
|
+ * "width": 459,
|
|
|
+ * "height": 99
|
|
|
+ * },
|
|
|
+ * "words": "南京市江宁区弘景大道3889号"
|
|
|
+ * },
|
|
|
+ * "公民身份号码": {
|
|
|
+ * "location": {
|
|
|
+ * "left": 443,
|
|
|
+ * "top": 681,
|
|
|
+ * "width": 589,
|
|
|
+ * "height": 45
|
|
|
+ * },
|
|
|
+ * "words": "330881199904173914"
|
|
|
+ * },
|
|
|
+ * "出生": {
|
|
|
+ * "location": {
|
|
|
+ * "left": 270,
|
|
|
+ * "top": 355,
|
|
|
+ * "width": 357,
|
|
|
+ * "height": 45
|
|
|
+ * },
|
|
|
+ * "words": "19990417"
|
|
|
+ * },
|
|
|
+ * "姓名": {
|
|
|
+ * "location": {
|
|
|
+ * "left": 267,
|
|
|
+ * "top": 176,
|
|
|
+ * "width": 152,
|
|
|
+ * "height": 50
|
|
|
+ * },
|
|
|
+ * "words": "伍云龙"
|
|
|
+ * },
|
|
|
+ * "性别": {
|
|
|
+ * "location": {
|
|
|
+ * "left": 269,
|
|
|
+ * "top": 262,
|
|
|
+ * "width": 33,
|
|
|
+ * "height": 52
|
|
|
+ * },
|
|
|
+ * "words": "男"
|
|
|
+ * },
|
|
|
+ * "民族": {
|
|
|
+ * "location": {
|
|
|
+ * "left": 492,
|
|
|
+ * "top": 279,
|
|
|
+ * "width": 30,
|
|
|
+ * "height": 37
|
|
|
+ * },
|
|
|
+ * "words": "汉"
|
|
|
+ * }
|
|
|
+ * },
|
|
|
+ * "words_result_num": 6
|
|
|
+ * }
|
|
|
+ *
|
|
|
+ * @return
|
|
|
+ */
|
|
|
+ public static JSONObject idcard(String image) {
|
|
|
+ try {
|
|
|
+ // 文件路径
|
|
|
+ byte[] imgData = FileUtil.readFileByBytes(image);
|
|
|
+
|
|
|
+ String imgStr = encryptImg(aesKey, imgData);
|
|
|
+
|
|
|
+ String imgParam = URLEncoder.encode(imgStr, "UTF-8");
|
|
|
+
|
|
|
+ String param = "id_card_side=" + "front" +
|
|
|
+ "&image=" + imgParam +
|
|
|
+ "&AESEncry=" + true;
|
|
|
+
|
|
|
+ String accessToken = getAccessToken();
|
|
|
+
|
|
|
+ String encryptResult = HttpUtil.post(url, accessToken, param);
|
|
|
+
|
|
|
+ String decryptResult = parseResult(encryptResult);
|
|
|
+ JSONObject jsonObject = JSON.parseObject(decryptResult);
|
|
|
+ return jsonObject;
|
|
|
+ } catch (Exception e) {
|
|
|
+ e.printStackTrace();
|
|
|
+ }
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 加密图片
|
|
|
+ *
|
|
|
+ * @param aesKey
|
|
|
+ * @param imgData
|
|
|
+ * @return
|
|
|
+ * @throws Exception
|
|
|
+ */
|
|
|
+ private static String encryptImg(String aesKey, byte[] imgData) throws Exception {
|
|
|
+ originAesKey = AesKeyUtil.parseAesKey(aesKey);
|
|
|
+ byte[] encImgBytes = AesUtil.encrypt(imgData, originAesKey);
|
|
|
+ String imgStr = Base64Util.encodeBase64(encImgBytes);
|
|
|
+ return imgStr;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 解密结果
|
|
|
+ *
|
|
|
+ * @param encryptResult
|
|
|
+ * @return
|
|
|
+ * @throws Exception
|
|
|
+ */
|
|
|
+ private static String parseResult(String encryptResult) throws Exception {
|
|
|
+ JSONObject obj = JSONObject.parseObject(encryptResult);
|
|
|
+ String result = obj.getString("result");
|
|
|
+ byte[] arr = Base64Util.decodeBase64(result);
|
|
|
+ String decryptResult = new String(AesUtil.decrypt(arr, originAesKey));
|
|
|
+ return decryptResult;
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ static class AesKeyUtil {
|
|
|
+ private static final String HEX = "0123456789abcdef";
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 获得原生的128位的aeskey
|
|
|
+ * 因为一个byte位8位最后生成的byte数组长度为16
|
|
|
+ * <p>
|
|
|
+ * 16 * 8 = 128
|
|
|
+ *
|
|
|
+ * @param hex
|
|
|
+ * @return
|
|
|
+ */
|
|
|
+ public static byte[] parseAesKey(String hex) throws Exception {
|
|
|
+ char[] data = hex.toCharArray();
|
|
|
+ if (data.length != 16) {
|
|
|
+ throw new Exception(" ase key illegal ");
|
|
|
+ }
|
|
|
+ return decode(hex.toCharArray());
|
|
|
+ }
|
|
|
+
|
|
|
+ private static byte[] decode(char[] data) throws IllegalArgumentException {
|
|
|
+ int len = data.length;
|
|
|
+
|
|
|
+ byte[] out = new byte[len];
|
|
|
+
|
|
|
+ for (int i = 0; i < len; i++) {
|
|
|
+ int f = toDigit(data[i]);
|
|
|
+ out[i] = (byte) (f);
|
|
|
+ }
|
|
|
+ return out;
|
|
|
+ }
|
|
|
+
|
|
|
+ private static int toDigit(char ch) {
|
|
|
+ return HEX.indexOf(ch);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ static class AesUtil {
|
|
|
+
|
|
|
+ private static final String ALGORITHM = "AES";
|
|
|
+
|
|
|
+ private static final String ALGORITHM_STR = "AES/ECB/PKCS5Padding";
|
|
|
+
|
|
|
+ /**
|
|
|
+ * aes 加密
|
|
|
+ */
|
|
|
+ private static byte[] encrypt(byte[] src, byte[] aesKey) throws Exception {
|
|
|
+ Cipher cipher = getCipher(aesKey, Cipher.ENCRYPT_MODE);
|
|
|
+ byte[] ret = cipher.doFinal(src);
|
|
|
+ return ret;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * aes 解密
|
|
|
+ */
|
|
|
+ public static byte[] decrypt(byte[] src, byte[] aesKey) throws Exception {
|
|
|
+ Cipher cipher = getCipher(aesKey, Cipher.DECRYPT_MODE);
|
|
|
+ byte[] original = cipher.doFinal(src);
|
|
|
+ return original;
|
|
|
+ }
|
|
|
+
|
|
|
+ private static Cipher getCipher(byte[] aesKey, int mode) throws Exception {
|
|
|
+ SecretKeySpec secretKeySpec = new SecretKeySpec(aesKey, ALGORITHM);
|
|
|
+ Cipher cipher = Cipher.getInstance(ALGORITHM_STR);
|
|
|
+ cipher.init(mode, secretKeySpec);
|
|
|
+ return cipher;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ static class Base64Util {
|
|
|
+
|
|
|
+ private static Base64.Encoder ENCODER = Base64.getEncoder();
|
|
|
+
|
|
|
+ // base64 加密
|
|
|
+ private static Base64.Decoder DECODER = Base64.getDecoder();
|
|
|
+
|
|
|
+ /**
|
|
|
+ * base64加密
|
|
|
+ *
|
|
|
+ * @param arr
|
|
|
+ * @return
|
|
|
+ */
|
|
|
+ private static String encodeBase64(byte[] arr) {
|
|
|
+ String base64 = null;
|
|
|
+ try {
|
|
|
+ base64 = ENCODER.encodeToString(arr);
|
|
|
+ } catch (Exception e) {
|
|
|
+ }
|
|
|
+ return base64;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * base64解密
|
|
|
+ *
|
|
|
+ * @param str
|
|
|
+ * @return
|
|
|
+ */
|
|
|
+ public static byte[] decodeBase64(String str) {
|
|
|
+ byte[] encodeBase64 = new byte[0];
|
|
|
+ try {
|
|
|
+ encodeBase64 = DECODER.decode(str);
|
|
|
+ } catch (Exception e) {
|
|
|
+ }
|
|
|
+ return encodeBase64;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ static final OkHttpClient HTTP_CLIENT = new OkHttpClient().newBuilder().build();
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 获取百度开放平台的AccessToken
|
|
|
+ * @return
|
|
|
+ */
|
|
|
+ public static String getAccessToken() {
|
|
|
+ MediaType mediaType = MediaType.parse("application/json");
|
|
|
+ RequestBody body = RequestBody.create(mediaType, "");
|
|
|
+ String url = "https://aip.baidubce.com/oauth/2.0/token";
|
|
|
+ /**
|
|
|
+ * grant_type: 必须参数,固定为client_credentials;
|
|
|
+ * client_id: 必须参数,应用的API Key;
|
|
|
+ * client_secret: 必须参数,应用的Secret Key;
|
|
|
+ */
|
|
|
+ String grantType = "client_credentials";
|
|
|
+ String clientId = "11111111111111";
|
|
|
+ String clientSecret = "22222222222222222";
|
|
|
+ String apiUrl = String.format("%s?grant_type=%s&client_id=%s&client_secret=%s",
|
|
|
+ url, grantType, clientId, clientSecret);
|
|
|
+
|
|
|
+ Request request = new Request.Builder()
|
|
|
+ .url(apiUrl)
|
|
|
+ .method("POST", body)
|
|
|
+ .addHeader("Content-Type", "application/json")
|
|
|
+ .addHeader("Accept", "application/json")
|
|
|
+ .build();
|
|
|
+ Response response = null;
|
|
|
+ try {
|
|
|
+ response = HTTP_CLIENT.newCall(request).execute();
|
|
|
+ } catch (IOException e) {
|
|
|
+ e.printStackTrace();
|
|
|
+ }
|
|
|
+ //todo 判断是否成功调用
|
|
|
+ //取出返回的access_token
|
|
|
+ JSONObject jsonObject = null;
|
|
|
+ String accessToken = null;
|
|
|
+ if (response != null) {
|
|
|
+ jsonObject = JSON.parseObject(response.toString());
|
|
|
+ accessToken = jsonObject.getString("access_token");
|
|
|
+ }
|
|
|
+ return accessToken;
|
|
|
+ }
|
|
|
+}
|