通过百度API识别身份证图片

正文

通过百度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*/@SneakyThrowspublic 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*/@SneakyThrowspublic 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;}@SneakyThrowspublic 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;}@SneakyThrowspublic 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;@Beanpublic 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 fail = checkIdCardFrontImg(validateIdCardDTO, idCardModel);if (fail != null) return fail;UserVO userVO = new UserVO();userVO.setRealName(idCardModel.getName());userVO.setIdCardNo(idCardModel.getCardNo());userVO.setAge(StringUtil.calculateAge(idCardModel.getCardNo()));userVO.setBirthday(DateUtil.parse(idCardModel.getBirthday(), DateUtil.SHORT_PATTERN_DATE));userVO.setSex("男".equals(idCardModel.getSex()) ? ApplicationConstant.SexEnum.MAN.getKey() : ApplicationConstant.SexEnum.WOMEN.getKey());Map result = new HashMap<>();result.put("user", userVO);return R.data(result);}/*** 校验身份证证明信息* @param validateIdCardDTO	validateIdCardDTO* @param idCardModel	idCardModel* @return	R*/private static R checkIdCardFrontImg(ValidateIdCardDTO validateIdCardDTO, IdCardModel idCardModel) {if (idCardModel == null) {return R.fail("无法获取身份证信息!");}if (!validateIdCardDTO.getName().equals(idCardModel.getName())) {return R.fail("身份证姓名不匹配!");}if (!validateIdCardDTO.getIdCardNo().equals(idCardModel.getCardNo())) {return R.fail("身份证件号不匹配!");}return null;}
@PostMapping("/validate-idcard")@ApiOperationSupport(order = 17)@ApiOperation(value = "校验身份证的合法性", notes = "传入身份证信息")public R validateIdCard(@Valid @RequestBody ValidateIdCardDTO validateIdCardDTO) {IdCardModel idCardModel = baiduAiTemplate.getIdCardModel(validateIdCardDTO.getFrontImg(), validateIdCardDTO.getBackImg());R fail = checkIdCardFrontImg(validateIdCardDTO, idCardModel);if (fail != null) return fail;String today = DateUtil.format(new Date(), DateUtil.SHORT_PATTERN_DATE);String expiryDate = idCardModel.getExpiryDate();if (Long.parseLong(today) > Long.parseLong(expiryDate)) {return R.fail("身份证已过期!");}User user = loginUser();user.setIsOcr(1);user.setRealName(idCardModel.getName());user.setIdCardNo(idCardModel.getCardNo());user.setBirthday(DateUtil.parse(idCardModel.getBirthday(), DateUtil.SHORT_PATTERN_DATE));user.setSex("男".equals(idCardModel.getSex()) ? 1 : 2);userService.updateById(user);Map result = new HashMap<>();result.put("access_token", baiduAiTemplate.token());result.put("user", loginUser());return R.data(result);}
@GetMapping("/baidu/verifyToken")@ApiOperationSupport(order = 16)@ApiOperation(value = "获取百度API方案verify_token")public R getBaiduVerifyToken() {User user = loginUser();if (user == null) {return R.fail("无法获取用户信息!");} else if (user.getIsOcr() == null || user.getIsOcr() != 1) {return R.fail("用户未做证件验证!");}String verifyToken = baiduAiTemplate.verifyToken();boolean isSubmitIdCardInfo = baiduAiTemplate.submitIdcardInfo(user.getIdCardNo(), user.getRealName(), verifyToken);if (isSubmitIdCardInfo) {return R.data(verifyToken);}return R.fail("无法获取验证码,请检查用户身份信息是否完整!");}
/*** 人脸核身校验*/@PostMapping("/face/verify")@ApiOperationSupport(order = 19)@ApiOperation(value = "人脸核身认证", notes = "通过人脸实名认证")public R certification(@Valid @RequestBody FaceVerifyDTO faceVerifyDTO) {User user = loginUser();if (user == null) {return R.fail("无法获取用户信息!");} else if (user.getIsOcr() == null || user.getIsOcr() != 1) {return R.fail("用户未做证件验证!");}boolean verifyResult = false;if (faceVerifyDTO.getVerifyToken() != null) {// H5通过校验码校验verifyResult = baiduAiTemplate.getFacePrintDetail(faceVerifyDTO.getVerifyToken());if (!verifyResult) {return R.fail("此认证流程尚未开始!");}} else {// APP通过图片校验verifyResult = baiduAiTemplate.verifyFaceScore(user.getIdCardNo(), user.getRealName(), faceVerifyDTO.getImage());// 上传图片到OSSString imageUrl = uploadImage(faceVerifyDTO.getImage(), null, "FACE_" + user.getName() + System.currentTimeMillis());user.setFaceImage(imageUrl);if (!verifyResult) {return R.fail("人脸核身认证失败,请确认图片的合法性!");}}user.setIsCertification(1);userService.updateById(user);return R.data(UserWrapper.build().entityVO(user));}
 

配置文件

application-dev.yml

ai:baidu:client-id: 123456client-secret: 123456grant-type: client_credentialsh5-plan-id: 1face-score: 80


本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!

相关文章