通过百度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
	 */
	@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 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());
			// 上传图片到OSS
			String 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: 123456
    client-secret: 123456
    grant-type: client_credentials
    h5-plan-id: 1
    face-score: 80

你可能感兴趣的:(JAVA,后端,百度,java,开发语言)