通过百度API识别身份证图片,并返回信息
BaiduAiTemplate
package cn.com.infox.core.ai;
import cn.com.infox.core.ai.model.IdCardModel;
import cn.com.infox.core.ai.props.AiBaiduProperties;
import cn.com.infox.core.tool.jackson.JsonUtil;
import cn.com.infox.core.tool.utils.OkHttpUtil;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.json.JSONObject;
import java.util.HashMap;
import java.util.Map;
/**
* Baidu AI Token Template
*
* @author Daniel
*/
@Slf4j
public class BaiduAiTemplate {
private final AiBaiduProperties aiBaiduProperties;
private String token;
private long expiresTime = 0L;
private static final int SECOND = 1000;
private static final String ACCESS_TOKEN = "access_token";
private static final String EXPIRES_IN = "expires_in";
private static final String VERIFY_TOKEN = "verify_token";
private static final String WORDS = "words";
private static final String WORDS_RESULT = "words_result";
private static final String RESULT = "result";
private static final String VERIFY_RESULT = "verify_result";
private static final String SCORE = "score";
private static final String GRANT_TYPE = "grant_type";
private static final String CLIENT_ID = "client_id";
private static final String CLIENT_SECRET = "client_secret";
private static final String CONTENT_TYPE = "Content-Type";
private static final String CONTENT_TYPE_FORM = "application/x-www-form-urlencoded";
private static final String CONTENT_TYPE_JSON = "application/json";
private static final String ID_CARD_SIDE = "id_card_side";
private static final String ID_CARD_SIDE_FRONT = "front";
private static final String ID_CARD_SIDE_BACK = "back";
private static final String IMAGE = "image";
private static final String DETECT_RISK = "detect_risk";
private static final String DETECT_PHOTO = "detect_photo";
private static final String TRUE = "true";
private static final String FALSE = "false";
/**
* 获取百度AI Token
*/
private static final String TOKEN_URL = "https://aip.baidubce.com/oauth/2.0/token";
/**
* 通过OCR获取证件信息
*/
private static final String ID_CARD_URL = "https://aip.baidubce.com/rest/2.0/ocr/v1/idcard";
/**
* 人脸实名认证(V4)接口
*/
private static final String FACE_V4_VERIFY_URL = "https://aip.baidubce.com/rest/2.0/face/v4/mingjing/verify";
/**
* 获取方案校验Token(H5)
*/
private static final String FACE_PRINT_VERIFY_TOKEN_GENERATE_URL = "https://aip.baidubce.com/rpc/2.0/brain/solution/faceprint/verifyToken/generate";
/**
* 指定用户信息上报接口(H5)
*/
private static final String FACE_PRINT_ID_CARD_SUBMIT_URL = "https://aip.baidubce.com/rpc/2.0/brain/solution/faceprint/idcard/submit";
/**
* 对比图片上传接口(H5)
*/
private static final String FACE_PRINT_UPLOAD_MATCH_IMAGE_URL = "https://aip.baidubce.com/rpc/2.0/brain/solution/faceprint/uploadMatchImage";
/**
* 查询认证结果接口(H5)
*/
private static final String FACE_PRINT_RESULT_DETAIL_URL = "https://aip.baidubce.com/rpc/2.0/brain/solution/faceprint/result/detail";
public BaiduAiTemplate(AiBaiduProperties aiBaiduProperties) {
this.aiBaiduProperties = aiBaiduProperties;
}
/**
* 获取百度AI的接口Token
*
* @return
*/
@SneakyThrows
public String token() {
if (this.token != null && (expiresTime < System.currentTimeMillis())) {
return this.token;
}
return getToken();
}
private String getToken() {
String result = "";
try {
long currentTime = System.currentTimeMillis();
Map queries = new HashMap<>();
queries.put(GRANT_TYPE, aiBaiduProperties.getGrantType());
queries.put(CLIENT_ID, aiBaiduProperties.getClientId());
queries.put(CLIENT_SECRET, aiBaiduProperties.getClientSecret());
result = OkHttpUtil.get(TOKEN_URL, queries);
JSONObject resultJson = new JSONObject(result);
this.token = resultJson.getString(ACCESS_TOKEN);
this.expiresTime = currentTime + (resultJson.getLong(EXPIRES_IN) * SECOND);
} catch (Exception e) {
log.error("获取百度AI token 失败:" + result, e);
}
return this.token;
}
/**
* 获取H5方案验证Token
*
* @return
*/
@SneakyThrows
public String verifyToken() {
return getVerifyToken();
}
private String getVerifyToken() {
String verifyToken = "";
String result = "";
try {
Map header = new HashMap();
header.put(CONTENT_TYPE, CONTENT_TYPE_JSON);
Map body = new HashMap();
body.put("plan_id", aiBaiduProperties.getH5PlanId());
String json = JsonUtil.toJson(body);
result = OkHttpUtil.postJson(FACE_PRINT_VERIFY_TOKEN_GENERATE_URL + "?" + ACCESS_TOKEN + "=" + token(), header, json);
JSONObject resultJson = new JSONObject(result);
verifyToken = resultJson.getJSONObject(RESULT).getString(VERIFY_TOKEN);
} catch (Exception e) {
log.error("获取百度AI应用方案的 verify token 失败:" + result, e);
}
return verifyToken;
}
@SneakyThrows
public IdCardModel getIdCardModel(String frontImg, String backImg) {
IdCardModel idCardModel = new IdCardModel();
String result = "";
try {
result = getIdCard(frontImg, ID_CARD_SIDE_FRONT);
JSONObject resultJson = new JSONObject(result);
idCardModel.setPhoto(resultJson.getString("photo"));
JSONObject wordsResult = resultJson.getJSONObject(WORDS_RESULT);
idCardModel.setName(wordsResult.getJSONObject("姓名").getString(WORDS));
idCardModel.setNation(wordsResult.getJSONObject("民族").getString(WORDS));
idCardModel.setAddress(wordsResult.getJSONObject("住址").getString(WORDS));
idCardModel.setCardNo(wordsResult.getJSONObject("公民身份号码").getString(WORDS));
idCardModel.setSex(wordsResult.getJSONObject("性别").getString(WORDS));
idCardModel.setBirthday(wordsResult.getJSONObject("出生").getString(WORDS));
result = getIdCard(backImg, ID_CARD_SIDE_BACK);
resultJson = new JSONObject(result);
wordsResult = resultJson.getJSONObject(WORDS_RESULT);
idCardModel.setExpiryDate(wordsResult.getJSONObject("失效日期").getString(WORDS));
idCardModel.setIssueOrg(wordsResult.getJSONObject("签发机关").getString(WORDS));
idCardModel.setIssueDate(wordsResult.getJSONObject("签发日期").getString(WORDS));
} catch (Exception e) {
log.error("获取身份证信息失败:" + result, e);
}
return idCardModel;
}
@SneakyThrows
public IdCardModel validateIdCardFrontImg(String frontImg) {
IdCardModel idCardModel = new IdCardModel();
String result = "";
try {
result = getIdCard(frontImg, ID_CARD_SIDE_FRONT);
JSONObject resultJson = new JSONObject(result);
idCardModel.setPhoto(resultJson.getString("photo"));
JSONObject wordsResult = resultJson.getJSONObject(WORDS_RESULT);
idCardModel.setName(wordsResult.getJSONObject("姓名").getString(WORDS));
idCardModel.setNation(wordsResult.getJSONObject("民族").getString(WORDS));
idCardModel.setAddress(wordsResult.getJSONObject("住址").getString(WORDS));
idCardModel.setCardNo(wordsResult.getJSONObject("公民身份号码").getString(WORDS));
idCardModel.setSex(wordsResult.getJSONObject("性别").getString(WORDS));
idCardModel.setBirthday(wordsResult.getJSONObject("出生").getString(WORDS));
} catch (Exception e) {
log.error("获取身份证信息失败:" + result, e);
}
return idCardModel;
}
private String getIdCard(String img, String side) {
String result = "";
try {
Map header = new HashMap();
header.put(CONTENT_TYPE, CONTENT_TYPE_FORM);
Map queries = new HashMap<>();
queries.put(ACCESS_TOKEN, token());
if (ID_CARD_SIDE_FRONT.equals(side)) {
queries.put(DETECT_PHOTO, TRUE);
queries.put(DETECT_RISK, FALSE);
queries.put(ID_CARD_SIDE, ID_CARD_SIDE_FRONT);
} else {
queries.put(ID_CARD_SIDE, ID_CARD_SIDE_BACK);
}
Map params = new HashMap<>();
params.put(IMAGE, img);
result = OkHttpUtil.post(ID_CARD_URL, header, queries, params);
} catch (Exception e) {
log.error("获取百度AI ID Card 失败:" + result, e);
}
return result;
}
/**
* 验证人脸(将人脸图片通过API对比后,看分值是否达标,默认分值80)
*
* @param idCardNo
* @param name
* @param image
* @return
*/
public boolean verifyFaceScore(String idCardNo, String name, String image) {
String result = "";
try {
Map header = new HashMap();
header.put(CONTENT_TYPE, CONTENT_TYPE_JSON);
Map body = new HashMap();
body.put("id_card_number", idCardNo);
body.put("name", name);
body.put(IMAGE, image);
String json = JsonUtil.toJson(body);
result = OkHttpUtil.postJson(FACE_V4_VERIFY_URL + "?" + ACCESS_TOKEN + "=" + token(), header, json);
JSONObject resultJson = new JSONObject(result);
double score = resultJson.getJSONObject(RESULT).getDouble(SCORE);
return score > aiBaiduProperties.getFaceScore();
} catch (Exception e) {
log.error("人脸校验失败:" + result, e);
}
return false;
}
/**
* 指定用户信息上报接口
*
* @param idCardNo 证件号
* @param name 证件姓名
* @param verifyToken 验证码
* @return 判断结果
*/
public boolean submitIdcardInfo(String idCardNo, String name, String verifyToken) {
String result = "";
try {
Map header = new HashMap();
header.put(CONTENT_TYPE, CONTENT_TYPE_JSON);
Map body = new HashMap();
body.put("id_no", idCardNo);
body.put("id_name", name);
body.put(VERIFY_TOKEN, verifyToken);
String json = JsonUtil.toJson(body);
result = OkHttpUtil.postJson(FACE_PRINT_ID_CARD_SUBMIT_URL + "?" + ACCESS_TOKEN + "=" + token(), header, json);
JSONObject resultJson = new JSONObject(result);
return resultJson.getBoolean("success");
} catch (Exception e) {
log.error("人脸校验失败:" + result, e);
}
return false;
}
public boolean uploadMatchImage(String image, String verifyToken) {
String result = "";
try {
Map header = new HashMap();
header.put(CONTENT_TYPE, CONTENT_TYPE_JSON);
Map body = new HashMap();
body.put(IMAGE, image);
body.put(VERIFY_TOKEN, verifyToken);
String json = JsonUtil.toJson(body);
result = OkHttpUtil.postJson(FACE_PRINT_UPLOAD_MATCH_IMAGE_URL + "?" + ACCESS_TOKEN + "=" + token(), header, json);
JSONObject resultJson = new JSONObject(result);
return resultJson.getBoolean("success");
} catch (Exception e) {
log.error("人脸校验失败:" + result, e);
}
return false;
}
public boolean getFacePrintDetail(String verifyToken) {
String result = "";
try {
Map header = new HashMap();
header.put(CONTENT_TYPE, CONTENT_TYPE_JSON);
Map body = new HashMap();
body.put(VERIFY_TOKEN, verifyToken);
String json = JsonUtil.toJson(body);
result = OkHttpUtil.postJson(FACE_PRINT_RESULT_DETAIL_URL + "?" + ACCESS_TOKEN + "=" + token(), header, json);
JSONObject resultJson = new JSONObject(result);
double score = resultJson.getJSONObject(RESULT).getJSONObject(VERIFY_RESULT).getDouble(SCORE);
return score > aiBaiduProperties.getFaceScore();
} catch (Exception e) {
log.error(".查询人脸认证结果失败:" + result, e);
}
return false;
}
}
AiBaiduProperties
package cn.com.infox.core.ai.props;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
@Data
@ConfigurationProperties(prefix = "ai.baidu")
public class AiBaiduProperties {
/**
* 应用的API Key
*/
private String clientId;
/**
* 应用的Secret Key
*/
private String clientSecret;
/**
* 固定为client_credentials
*/
private String grantType = "client_credentials";
/**
* H5 方案ID
*/
private int h5PlanId = 1;
/**
* 人脸阀值
*/
private double faceScore = 80.00;
}
BaiduConfiguration
package cn.com.infox.core.ai.config;
import cn.com.infox.core.ai.props.AiBaiduProperties;
import cn.com.infox.core.ai.BaiduAiTemplate;
import lombok.AllArgsConstructor;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* Baidu AI 配置类
*
* @author Admin
*/
@Configuration
@AllArgsConstructor
@EnableConfigurationProperties(AiBaiduProperties.class)
@ConditionalOnProperty(value = "ai.baidu.client-id")
public class BaiduConfiguration {
private AiBaiduProperties aiBaiduProperties;
@Bean
public BaiduAiTemplate baiduTokenTemplateTemplate() {
return new BaiduAiTemplate(aiBaiduProperties);
}
}
IdCardModel
package cn.com.infox.core.ai.model;
import lombok.Data;
/**
* 身份证信息
*
* @author Daniel
*/
@Data
public class IdCardModel {
/**
* 姓名
*/
private String name;
/**
* 民族
*/
private String nation;
/**
* 地址
*/
private String address;
/**
* 卡号
*/
private String cardNo;
/**
* 生日
*/
private String birthday;
/**
* 性别
*/
private String sex;
/**
* 图片
*/
private String photo;
/**
* 签发日期
*/
private String issueDate;
/**
* 签发机构
*/
private String issueOrg;
/**
* 失效日期
*/
private String expiryDate;
}
Controller
@PostMapping("/validate-idCard-frontImg")
@ApiOperationSupport(order = 21)
@ApiOperation(value = "根据身份证正面获取用户信息", notes = "根据身份证正面获取用户信息")
public R validateIdCardFrontImg(@Valid @RequestBody ValidateIdCardDTO validateIdCardDTO) {
IdCardModel idCardModel = baiduAiTemplate.validateIdCardFrontImg(validateIdCardDTO.getFrontImg());
R
application-dev.yml
ai:
baidu:
client-id: 123456
client-secret: 123456
grant-type: client_credentials
h5-plan-id: 1
face-score: 80