使用场景:
远程身份认证
自动识别录入用户身份/企业资质信息,应用于金融、政务、保险、电商、直播等场景,对用户、商家、主播进行实名身份认证,有效降低用户输入成本,控制业务风险
文档电子化
识别提取各类办公文档、合同文件、企业年报、法律卷宗等纸质文档中的文字信息,并基于位置信息进行比对、结构化处理,提高信息录入、存档、检索效率
交通出行
实现卡证、车辆信息的快速录入,提升比对效率,适用于司机身份核验、车主信息管理、智慧停车、卡口通行、车辆维修保养等场景
快递物流
实现快递分发全链路智能化升级,满足身份核验、智能寄件下单,运输车辆管理、快递单识别等不同场景需求。同时助力大宗货运物流过磅提效
财税报销
对10 余种常见税务发票、差旅票据自动分类、识别、录入,可快速对接国税平台进行增值税发票验真,适用于企业税务核算及内部报销场景,释放企业人力,简化业务流程
医疗保险
识别患者身份信息/各类医疗票据/医疗仪器盘数据,提升信息录入效率,助力提高保险理赔整体时效,并辅助病患管理、健康监测、处方单电子化等
识别实战
身份证验证
使用百度智能云的OCR身份证识别
鉴权认证机制
获取到access_token
通过API Key和Secret Key获取的access_token,参考"Access Token获取"
鉴权的主要目的是获取Access_token。Access_token是用户的访问令牌,承载了用户的身份、权限等信息。
1.获取AK/SK
创建应用
2.添加到nacos配置中
3.在业务层使用@Value获取
4.获取Access_token
使用下面编写好的工具类BaiduOcrApi 。
5.controller层
java
@Operation(summary = "识别身份证")
@Parameters({
@Parameter(name = "type", description = "back:国徽面;front:照片面", required = true, in = ParameterIn.QUERY)
})
@PostMapping("/idCard")
public SimpleResponse<OCRIdCardResponse> recognizeIdCardBack(@RequestPart(name = "file") MultipartFile file,
@RequestParam("type") String type) {
return SimpleResponse.success(ocrService.recognizeIdCard(file, type));
}
6.service层
java
@Value("${ocr.apiKey}")
private String apiKey;
@Value("${ocr.secretKey}")
private String secretKey;
@Resource
private ObjectMapper objectMapper;
@Resource
private RedissonClientTemplate redissonClientTemplate;
/**
* 识别身份证
*
* @param file 文件
* @param type 类型
* @return {@link OCRIdCardResponse}
*/
@Override
@SneakyThrows
public OCRIdCardResponse recognizeIdCard(MultipartFile file, String type) {
if (file == null || file.isEmpty()) {
log.info("---------- 文件内容为空 ----------");
throw new AppRuntimeException(ResponseCode.OPERATION_FAILED);
}
InputStream inputStream = file.getInputStream();
// 获取access_token
String accessToken = redissonClientTemplate.get(RedisKeyConstants.OCR_ACCESS_TOKEN);
if (StringUtils.isEmpty(accessToken)) {
accessToken = BaiduOcrApi.getAccessToken(apiKey, secretKey);
// 保存accessToken到redis,有效时间为29天
redissonClientTemplate.setex(RedisKeyConstants.OCR_ACCESS_TOKEN, accessToken, 29L, TimeUnit.DAYS);
}
// ocr识别
String result = BaiduOcrApi.recognizeIDCardResult(inputStream, accessToken, type);
OCRResult orcIdCardResult = objectMapper.readValue(result, OCRResult.class);
if (orcIdCardResult == null || !"normal".equals(orcIdCardResult.getImage_status()) || orcIdCardResult.getWords_result_num() <= 0) {
throw new AppRuntimeException(ResponseCode.OCR_API_ERROR);
}
OCRIdCardResponse orcIdCardResponse = new OCRIdCardResponse();
Map<String, OCRResult.wordsModel> wordsResult = orcIdCardResult.getWords_result();
// 获取结果
if ("back".equals(type)) {
// 身份证国徽面
OCRResult.wordsModel wordsModel = wordsResult.get(OcrConstant.EXPIRATION_DATE);
if (wordsModel == null) {
throw new AppRuntimeException(ResponseCode.OCR_API_ERROR);
}
orcIdCardResponse.setExpirationDate(wordsModel.getWords());
} else {
// 身份证头像面
OCRResult.wordsModel wordsModel1 = wordsResult.get(OcrConstant.NAME);
if (wordsModel1 == null) {
throw new AppRuntimeException(ResponseCode.OCR_API_ERROR);
}
orcIdCardResponse.setName(wordsModel1.getWords());
OCRResult.wordsModel wordsModel2 = wordsResult.get(OcrConstant.ID_NUMBER);
if (wordsModel2 == null) {
throw new AppRuntimeException(ResponseCode.OCR_API_ERROR);
}
orcIdCardResponse.setIdNumber(wordsModel2.getWords());
}
// TODO 保存照片到OSS
return orcIdCardResponse;
6.百度ocr请求工具类
java
import cn.hutool.json.JSONObject;
import okhttp3.*;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.Base64;
/**
* @ClassName: BaiduOcrApi
* @Author: wujiada
* @Date: 2024/12/16 10:21
* @Description: 使用API Key和Secret Key获取Access Token,获取识别结果
*/
public class BaiduOcrApi {
private static final OkHttpClient HTTP_CLIENT = new OkHttpClient().newBuilder().build();
/**
* 从用户的AK,SK生成鉴权签名(Access Token)
*
* @return 鉴权签名(Access Token)
* @throws IOException IO异常
*/
public static String getAccessToken(String apiKey, String secretKey) throws Exception {
MediaType mediaType = MediaType.parse("application/x-www-form-urlencoded");
RequestBody body = RequestBody.create(mediaType, "grant_type=client_credentials&client_id=" + apiKey
+ "&client_secret=" + secretKey);
Request request = new Request.Builder()
.url("https://aip.baidubce.com/oauth/2.0/token")
.method("POST", body)
.addHeader("Content-Type", "application/x-www-form-urlencoded")
.build();
Response response = HTTP_CLIENT.newCall(request).execute();
assert response.body() != null;
return new JSONObject(response.body().string()).get("access_token", String.class);
}
/**
* <p>请求百度OCR识别身份证</p>
*
* @param inputStream 文件输入流
* @param accessToken 访问百度云API的token
* @param type: back:国徽面;front:照片面
* @return {@link String}
* @author wujiada
* @since 2024/12/16 11:35
*/
public static String recognizeIDCardResult(InputStream inputStream, String accessToken, String type) throws Exception {
// 读取图片文件并转换为Base64编码
// 将输入流转换为字节数组
byte[] imageBytes = readInputStream(inputStream);
// 使用Base64编码字节数组
String base64EncodedImage = Base64.getEncoder().encodeToString(imageBytes);
MediaType mediaType = MediaType.parse("application/x-www-form-urlencoded");
// front:身份证含照片的一面
// back:身份证带国徽的一面
RequestBody body = RequestBody.create(mediaType, "image=" + URLEncoder.encode(base64EncodedImage, StandardCharsets.UTF_8)
+ "&id_card_side=" + type + "&detect_ps=false&detect_risk=false&detect_quality=false&detect_photo=false&detect_card=false&detect_direction=false");
Request request = new Request.Builder()
.url("https://aip.baidubce.com/rest/2.0/ocr/v1/idcard?access_token=" + accessToken)
.method("POST", body)
.addHeader("Content-Type", "application/x-www-form-urlencoded")
.addHeader("Accept", "application/json")
.build();
Response response = HTTP_CLIENT.newCall(request).execute();
assert response.body() != null;
return response.body().string();
}
/**
* <p>请求百度OCR识别营业执照</p>
*
* @param inputStream 文件输入流
* @param accessToken 访问百度云API的token
* @return {@link String}
* @author wujiada
* @since 2024/12/16 11:35
*/
public static String recognizeBusinessLicenseResult(InputStream inputStream, String accessToken) throws Exception {
// 读取图片文件并转换为Base64编码
// 将输入流转换为字节数组
byte[] imageBytes = readInputStream(inputStream);
// 使用Base64编码字节数组
String base64EncodedImage = Base64.getEncoder().encodeToString(imageBytes);
MediaType mediaType = MediaType.parse("application/x-www-form-urlencoded");
RequestBody body = RequestBody.create(mediaType, "image=" + URLEncoder.encode(base64EncodedImage, StandardCharsets.UTF_8));
Request request = new Request.Builder()
.url("https://aip.baidubce.com/rest/2.0/ocr/v1/business_license?access_token=" + accessToken)
.method("POST", body)
.addHeader("Content-Type", "application/x-www-form-urlencoded")
.addHeader("Accept", "application/json")
.build();
Response response = HTTP_CLIENT.newCall(request).execute();
assert response.body() != null;
return response.body().string();
}
/**
* <p>从输入流中读取所有字节并将它们存储在ByteArrayOutputStream</p>
*
* @param inputStream 文件输入流
* @return {@link byte[]}
* @author wujiada
* @since 2024/12/16 11:37
*/
private static byte[] readInputStream(InputStream inputStream) throws IOException {
// 使用ByteArrayOutputStream收集字节
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
byte[] buffer = new byte[1024];
int bytesRead;
// 从输入流中读取数据直到EOF
while ((bytesRead = inputStream.read(buffer)) != -1) {
byteArrayOutputStream.write(buffer, 0, bytesRead);
}
// 将收集的字节转换为字节数组
return byteArrayOutputStream.toByteArray();
}
}
7.ocrAPI接收结果实体类
java
/**
* @ClassName: OCRResult
* @Author: wujiada
* @Date: 2024/12/16 11:45
* @Description: 请求百度OCRAPI识别返回结果
*/
@Data
@Schema(description = "请求百度ORC识别API身份证返回结果")
public class OCRResult implements Serializable {
@Schema(description = "唯一的log id,用于问题定位")
private Long log_id;
@Schema(description = "识别结果数,表示words_result的元素个数")
private Long words_result_num;
@Schema(description = "定位和识别结果数组")
private Map<String, wordsModel> words_result;
/* normal-识别正常
reversed_side-身份证正反面颠倒
non_idcard-上传的图片中不包含身份证
blurred-身份证模糊
other_type_card-其他类型证照
over_exposure-身份证关键字段反光或过曝
over_dark-身份证欠曝(亮度过低)
unknown-未知状态*/
@Schema(description = "识别状态")
private String image_status;
@Data
public static class wordsModel {
private Object location;
private String words;
}
}
总结
通过以上操作,就可以实现前端上传身份证文件,然后发送到百度云OCR,识别校验身份证。