文章目录

  • 0.文档
  • 1.application
  • 2.dto
  • 3.constant
  • 4.service

0.文档

 [官方文档](https://faceid.com/pages/documents)

1.application

server:port: 80megvii:appKey: XXXsecret: XXX# 验证通过后跳转的页面returnUrl: https://www.pilipili.com/# 验证后回调的接口notifyUrl: https://www.pilipili.com/webTitle: 代码生涯

2.dto

@Data
@Builder
public class H5GetResultDTO {@ApiModelProperty(value = "调用此API的api_key", required = true)private String api_key;@ApiModelProperty(value = "调用此API的api_key的secret", required = true)private String api_secret;@ApiModelProperty(value = "通过 get_token, notify_url 或者 return_url 返回的活体业务编号。",required = true)private String biz_id;@ApiModelProperty(value = "是否返回活体图像数据:\n" +"0(默认):不需要图像\n" +"1:需要返回最佳活体质量图(image_best,当procedure_type为\"video\",\"still\"或\"flash\"时有效)\n" +"2:需要返回身份证人像面图像\n" +"3:需要返回身份证国徽面图像\n" +"4:需要返回所有图像\n" +"5:需要返回正脸自拍照片(仅当procedure_type为selfie时有效)\n" +"6:需要返回侧脸自拍照片(仅当procedure_type为selfie时有效)", required = true)private String return_image;
}@Data
@Builder
public class H5GetTokenDTO {@ApiModelProperty("调用此API的api_key")private String api_key;@ApiModelProperty("调用此API的api_key的secret")private String api_secret;@ApiModelProperty("用户完成或取消验证后网页跳转的目标URL")private String return_url;@ApiModelProperty("用户完成验证、取消验证、或验证超时后,由FaceID服务器请求客户服务器的URL。")private String notify_url;@ApiModelProperty("客户业务流水号,该号必须唯一。并会在notify和return时原封不动的返回给您的服务器,以帮助您确认每一笔业务的归属。")private String biz_no;@ApiModelProperty("验证网页展示用的标题文字,此参数默认为空,此时系统将采用默认的标题。")private String web_title;@ApiModelProperty("设定本次服务的类型,目前支持的比对类型为“KYC验证”(取值“1”)或“人脸比对”(取值“0”)。传递其他值调用将识别,返回错误码400(BAD_ARGUMENTS)。\n" +"“1”表示KYC验证,表示最终的用户自拍照片将于参考照片比对。\n" +"“0”表示人脸比对,FaceID将使用用户自己提供的照片(参数image_ref[x])作为比对人脸照。\n" +"请注意:\n" +"本参数影响验证流程中是否存在身份证拍摄环节:如果为“1”,则可选择包含身份证拍摄;如果为“0”,验证流程中将没有身份证拍摄。\n" +"本参数取什么值将决定下面“二选一”参数组使用哪一组参数。")private String comparison_type;@ApiModelProperty("传递参数“0”,“1”,“2”,“3”或“4”,表示获取用户身份证信息的方法。传递其他值调用将识别,返回错误码400(BAD_ARGUMENTS)。\n" +"0:不拍摄身份证,而是通过 idcard_name / idcard_number 参数传入;\n" +"1:仅拍摄身份证人像面,可获取人像面所有信息;\n" +"2:拍摄身份证人像面和身份证国徽面,可获取身份证所有信息;\n" +"3:不拍摄身份证,但会要求用户在界面上输入身份证号和姓名;\n" +"4:拍摄身份证人像面或用户输入身份证号和姓名,用户可在界面上自行选择身份证录入方法。注意:该参数只有在控制台中选择使用“浅色主题”时才生效,若未应用浅色主题而传入4,则返回错误码400(BAD_ARGUMENTS)。")private String idcard_mode;/*** idcard_mode = 0 时,idcard_name idcard_number 这两个参数必须传;在其他情况下可以不传,即使传递了也不会使用。*/@ApiModelProperty("idcard_name, 需要KYC验证对象的姓名,使用UTF-8编码;")private String idcard_name;@ApiModelProperty("idcard_number, 需要KYC验证对象的身份证号,也就是一个18位长度的字符串。")private String idcard_number;
}@Data
@ConfigurationProperties(prefix = "megvii")
@Component
public class MegviiProperties {private String secret;private String appKey;private String returnUrl;private String notifyUrl;private String webTitle;}

3.constant

@Data
public class MsgResult<T> implements Serializable {public static final String CODE_SUCCESS = "0";public static final String MESSAGE_SUCCESS = "success";@ApiModelProperty("状态码,0成功非0失败")private String code;@ApiModelProperty("状态码描述,0success非0失败原因")private String message;@ApiModelProperty("返回数据")private T data;private MsgResult(String code, String message, T data) {this.code = code;this.message = message;this.data = data;}public static MsgResult success() {return new MsgResult(CODE_SUCCESS, MESSAGE_SUCCESS, null);}public static <T> MsgResult success(T data) {return new MsgResult(CODE_SUCCESS, MESSAGE_SUCCESS, data);}public static <T> MsgResult success(T data, String message) {return new MsgResult(CODE_SUCCESS, message, data);}public static MsgResult error(ErrorCode errorCode, String appendMessage) {String message = String.format(errorCode.getMessage(), appendMessage == null ? "" : appendMessage);return new MsgResult(errorCode.getCode(), message, null);}public static MsgResult error(ErrorCode errorCode) {return new MsgResult(errorCode.getCode(), errorCode.getMessage(), null);}public static MsgResult error(String code, String message) {return new MsgResult(code, message, null);}public static MsgResult error(String message) {return new MsgResult(ErrorCode.OPER_FAIL.getCode(), message, null);}public boolean hasSuccess() {return CODE_SUCCESS.equals(this.code);}@Overridepublic String toString() {StringBuilder sb = new StringBuilder("MsgResult{");sb.append("code='").append(this.code).append('\'');sb.append(", message='").append(this.message).append('\'');sb.append(", data=").append(this.data);sb.append('}');return sb.toString();}public String toSimpleString() {StringBuilder sb = new StringBuilder("MsgResult{");sb.append("code='").append(this.code).append('\'');sb.append(", message='").append(this.message).append('\'');sb.append('}');return sb.toString();}public String getCode() {return this.code;}public String getMessage() {return this.message;}public T getData() {return this.data;}
}public class ErrorCode implements Serializable {public static final ErrorCode PARAM_REQUIRED = new ErrorCode("4001", "参数:%s不能为空");public static final ErrorCode PARAM_INVALID = new ErrorCode("4002", "参数:%s格式无效");public static final ErrorCode SIGN = new ErrorCode("4003", "参数签名验证失败");public static final ErrorCode AUTHORITY = new ErrorCode("4004", "您没有权限访问该接口");public static final ErrorCode DECRYPT = new ErrorCode("4005", "请求数据解密失败");public static final ErrorCode INVALID_CALLER = new ErrorCode("4006", "无效的调用方");public static final ErrorCode UPLOAD_TYPE = new ErrorCode("4007", "您上传的文件类型不允许");public static final ErrorCode UPLOAD_SIZE = new ErrorCode("4008", "您上传的文件大小不能超过[%s]KB");public static final ErrorCode SYSTEM_BUSY = new ErrorCode("4009", "服务器繁忙,请稍后重试");public static final ErrorCode NEED_LOGIN = new ErrorCode("4010", "登录超时,请重新登录");public static final ErrorCode OPER_FAIL = new ErrorCode("4011", "操作失败:%s");public static final ErrorCode SERVER = new ErrorCode("5000", "服务器内部错误:%s");public static final ErrorCode SERVER_REDIS = new ErrorCode("5001", "服务器内部错误:%s");public static final ErrorCode SERVER_MYSQL = new ErrorCode("5002", "服务器内部错误:%s");public static final ErrorCode SERVER_ES = new ErrorCode("5003", "服务器内部错误:%s");public static final ErrorCode SERVER_HTTP = new ErrorCode("5004", "服务器内部错误:%s");public static final ErrorCode SERVER_CASSANDRA = new ErrorCode("5005", "服务器内部错误:%s");public static final ErrorCode SERVER_ORACLE = new ErrorCode("5006", "服务器内部错误:%s");private String code;private String message;public ErrorCode(String code, String message) {this.code = code;this.message = message;}public String getCode() {return this.code;}public String getMessage() {return this.message;}
}public class MegviiConstant {public static final String GET_TOKEN_URL = "https://api.megvii.com/faceid/lite/get_token";public static final String GET_RESULT__URL = "https://api.megvii.com/faceid/lite/get_result";public static final String ERROR_MESSAGE = "error_message";/*** 表示目前 FaceID Lite 的使用状态*/public static final String OK = "OK";private static final String ERROR_STATUS_NOT_STARTED = "NOT_STARTED";private static final String ERROR_STATUS_PROCESSING = "PROCESSING";private static final String ERROR_STATUS_WEBRTC_UNSUPPORTED = "WEBRTC_UNSUPPORTED";private static final String ERROR_STATUS_FAILED = "FAILED";private static final String ERROR_STATUS_CANCELLED = "CANCELLED";private static final String ERROR_STATUS_TIMEOUT = "TIMEOUT";/*** 人脸比对结果*/private static final String VERIFY_ERROR_MESSAGE_NO_SUCH_ID_NUMBER = "NO_SUCH_ID_NUMBER";private static final String VERIFY_ERROR_MESSAGE_ID_NUMBER_NAME_NOT_MATCH = "ID_NUMBER_NAME_NOT_MATCH";private static final String VERIFY_ERROR_MESSAGE_IMAGE_ERROR_UNSUPPORTED_FORMAT = "IMAGE_ERROR_UNSUPPORTED_FORMAT";private static final String VERIFY_ERROR_MESSAGE_NO_FACE_FOUND = "NO_FACE_FOUND";private static final String VERIFY_ERROR_MESSAGE_DATA_SOURCE_ERROR = "DATA_SOURCE_ERROR";private static final String VERIFY_ERROR_MESSAGE_INTERNAL_ERROR = "INTERNAL_ERROR";/*** 活体检测结果*/public static final String LIVENESS_RESULT_PASS = "PASS";private static Map<String, String> ERROR_STATUS_MAP = Maps.newHashMap();private static Map<String, String> VERIFY_ERROR_MESSAGE__MAP = Maps.newHashMap();static {ERROR_STATUS_MAP.put(ERROR_STATUS_NOT_STARTED, "还没有开始验证");ERROR_STATUS_MAP.put(ERROR_STATUS_PROCESSING, "正在进行 FaceID Lite 验证");ERROR_STATUS_MAP.put(ERROR_STATUS_WEBRTC_UNSUPPORTED, "表示浏览器不支持引起失败");ERROR_STATUS_MAP.put(ERROR_STATUS_FAILED, "验证流程未完成或出现异常");ERROR_STATUS_MAP.put(ERROR_STATUS_CANCELLED, "用户主动取消了验证流程");ERROR_STATUS_MAP.put(ERROR_STATUS_TIMEOUT, "流程超时");VERIFY_ERROR_MESSAGE__MAP.put(VERIFY_ERROR_MESSAGE_NO_SUCH_ID_NUMBER, "没有此身份证号码的记录");VERIFY_ERROR_MESSAGE__MAP.put(VERIFY_ERROR_MESSAGE_ID_NUMBER_NAME_NOT_MATCH, "身份证号码与提供的姓名不匹配");VERIFY_ERROR_MESSAGE__MAP.put(VERIFY_ERROR_MESSAGE_IMAGE_ERROR_UNSUPPORTED_FORMAT, "姓名和身份证号正确,但图片无法解析或者没有可比对图片");VERIFY_ERROR_MESSAGE__MAP.put(VERIFY_ERROR_MESSAGE_NO_FACE_FOUND, "对应的图像没有检测到人脸");VERIFY_ERROR_MESSAGE__MAP.put(VERIFY_ERROR_MESSAGE_DATA_SOURCE_ERROR, "调用比对数据发生错误");VERIFY_ERROR_MESSAGE__MAP.put(VERIFY_ERROR_MESSAGE_INTERNAL_ERROR, "服务器内部错误,请及时联系运营人员");}/*** 获取FaceID Lite 的使用状态* @param status* @return*/public static String getStatusDesc(String status) {return StringUtils.isNotEmpty(ERROR_STATUS_MAP.get(status)) ? ERROR_STATUS_MAP.get(status) : OK;}/*** 获取人脸比对结果错误信息* @param errorMessage* @return*/public static String getVerifyResultErrorMessage(String errorMessage) {return StringUtils.isNotEmpty(VERIFY_ERROR_MESSAGE__MAP.get(errorMessage)) ? VERIFY_ERROR_MESSAGE__MAP.get(errorMessage) : OK;}
}

4.service

package com.raven.springboot.faceid.megvii.service;import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.raven.springboot.common.constant.MegviiConstant;
import com.raven.springboot.common.constant.MsgResult;
import com.raven.springboot.common.properties.MegviiProperties;
import com.raven.springboot.common.utils.HttpClientUtil;
import com.raven.springboot.faceid.megvii.dto.H5GetResultDTO;
import com.raven.springboot.faceid.megvii.dto.H5GetTokenDTO;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;import java.util.Map;
import java.util.Objects;/*** @PackageName: com.raven.springboot.service.faceid.megvii* @ClassName: FaceRecognitionService* @Blame: raven* @Date: 2021-08-02 15:35* @Description:*/
@Service
@Slf4j
public class FaceRecognitionService {@Autowiredprivate MegviiProperties megviiProperties;public MsgResult getToken(String bizNo, String idcardNumber, String idcardName) {// 构建请求参数H5GetTokenDTO getTokenDTO = builderH5GetTokenDTO(bizNo, idcardNumber, idcardName);// 调用获取tokenUrlString responseJson =  requestMegviiGetTokenUrl(getTokenDTO);// 返回调用结果return pareseGetTokenResponseJson(responseJson);}public MsgResult getResult(String bizNo){// 构建请求参数H5GetResultDTO getResultDTO = builderH5GetResultDTO(bizNo);// 调用获取tokenUrlString responseJson =  requestMegviiGetResultUrl(getResultDTO);// 返回调用结果return paresGetResultResponseJson(responseJson);}private MsgResult paresGetResultResponseJson(String responseJson) {JSONObject jsonObject = JSONObject.parseObject(responseJson);String errorMessage = jsonObject.getString(MegviiConstant.ERROR_MESSAGE);if (StringUtils.isNotBlank(errorMessage)){log.info("Megvii | 获取result请求失败,失败原因 {}",errorMessage);return MsgResult.error("获取result请求失败");}MsgResult msgResult = this.checkReturnDataInfo(JSON.toJSONString(jsonObject));if (!msgResult.hasSuccess()){return msgResult;}return MsgResult.success(jsonObject);}private String requestMegviiGetResultUrl(H5GetResultDTO getResultDTO) {Map<String,String> map = JSON.parseObject(JSON.toJSONString(getResultDTO), Map.class);return HttpClientUtil.doGet(MegviiConstant.GET_RESULT__URL, map);}private H5GetResultDTO builderH5GetResultDTO(String bizNo) {return H5GetResultDTO.builder().api_key(megviiProperties.getAppKey()).api_secret(megviiProperties.getSecret()).biz_id(bizNo).return_image("4").build();}private MsgResult pareseGetTokenResponseJson(String responseJson) {JSONObject jsonObject = JSONObject.parseObject(responseJson);String errorMessage = jsonObject.getString(MegviiConstant.ERROR_MESSAGE);if (StringUtils.isNotBlank(errorMessage)){log.info("Megvii | 获取token请求失败,失败原因 {}",errorMessage);return MsgResult.error("获取token请求失败");}return MsgResult.success(jsonObject);}private String requestMegviiGetTokenUrl(H5GetTokenDTO getTokenDTO) {Map<String,String> map = JSON.parseObject(JSON.toJSONString(getTokenDTO), Map.class);return HttpClientUtil.doPost(MegviiConstant.GET_TOKEN_URL, map);}private H5GetTokenDTO builderH5GetTokenDTO(String bizNo, String idcardNumber, String idcardName) {return H5GetTokenDTO.builder().api_key(megviiProperties.getAppKey()).api_secret(megviiProperties.getSecret()).return_url(megviiProperties.getReturnUrl()).notify_url(megviiProperties.getNotifyUrl()).biz_no(bizNo).web_title(megviiProperties.getWebTitle())// “1”表示KYC验证,表示最终的用户自拍照片将于参考照片比对.comparison_type("1")// 0:不拍摄身份证,而是通过 idcardName / idcardNumber 参数传入;.idcard_mode("0").idcard_number(idcardNumber).idcard_name(idcardName).build();}/*** 校验人脸识别信息** @param dataJson* @return*/public MsgResult checkReturnDataInfo(String dataJson) {if (StringUtils.isEmpty(dataJson)) {log.error("Megvii | 旷视人脸识别消息接收错误,dataJson = {}", dataJson);return MsgResult.error("人脸识别错误!");}JSONObject dataJsonObject = JSONObject.parseObject(dataJson);// 检验FaceID Lite 的使用状态String requestId = dataJsonObject.getString("request_id");String status = dataJsonObject.getString("status");String statusDesc = MegviiConstant.getStatusDesc(status);if (!StringUtils.equals(MegviiConstant.OK, statusDesc)) {log.error("Megvii | 旷视人脸识别消息接收错误, request_id:{}, 错误原因:{}", requestId, statusDesc);return MsgResult.error("人脸识别错误!");}// 活体检测结果JSONObject livenessResult = dataJsonObject.getJSONObject("liveness_result");String result = livenessResult.getString("result");if (!StringUtils.equals(MegviiConstant.LIVENESS_RESULT_PASS, result)) {log.error("Megvii | 旷视人脸识别消息接收错误, 活体检测失败, request_id:{}", requestId);return MsgResult.error("人脸识别错误!");}// 人脸比对结果风险JSONObject verifyResult = dataJsonObject.getJSONObject("verify_result");if (this.verifyResultRisk(verifyResult, requestId)) {return MsgResult.error("人脸识别错误!");}return MsgResult.success();}/*** 校验是否为同一人** @param verifyResult* @param requestId* @return*/private boolean verifyResultRisk(JSONObject verifyResult, String requestId) {if (Objects.isNull(verifyResult)) {return true;}String verifyResultErrorMessage = MegviiConstant.getVerifyResultErrorMessage(MegviiConstant.ERROR_MESSAGE);if (!StringUtils.equals(MegviiConstant.OK, verifyResultErrorMessage)) {log.error("Megvii | 旷视人脸识别消息接收错误, 在做人脸比对的时候出现错误, request_id:{}, 错误原因:{}", requestId, verifyResult.getString(MegviiConstant.ERROR_MESSAGE));return true;}JSONObject resultFaceid = verifyResult.getJSONObject("result_faceid");// 综合分数的置信度Double confidence = resultFaceid.getDouble("confidence");JSONObject thresholds = resultFaceid.getJSONObject("thresholds");// 风险为万分之一的置信度阈值Double score = thresholds.getDouble("1e-4");if (confidence < score) {log.error("Megvii | 旷视人脸识别消息接收错误, 系统认证不是同一个人, request_id:{}", requestId);return true;}return false;}}

技术使用总结-旷视人脸识别-(APP中H5接入)相关推荐

  1. 微软旷视人脸识别100%失灵!北京十一学校校友新研究「隐身衣」,帮你保护照片隐私数据...

    萧箫 鱼羊 发自 凹非寺 量子位 报道 | 公众号 QbitAI 左图,右图,你能看出区别吗? 其实,算法已经悄悄给右边的照片加上了微小的修改. 但就是这样肉眼根本看不出来的扰动,就能100%骗过来自 ...

  2. 微软旷视人脸识别100%失灵!照片「隐身衣」,帮你保护照片隐私数据

    本文经AI新媒体量子位(公众号ID:QbitAI)授权转载,转载请联系出处. 左图,右图,你能看出区别吗? 其实,算法已经悄悄给右边的照片加上了微小的修改. 但就是这样肉眼根本看不出来的扰动,就能10 ...

  3. 旷视人脸识别SDK 粗略分类剖析

    根据目录可以大致看到一套完整的SDK 函数分类.使用时根据demo按需查看sdk. 旷视SDK API接口 目录 旷视SDK API接口 1.整体SDK的操作 1.1 获取版本信息getVersion ...

  4. 人脸识别APP技术开发是如何实现的?

    人脸识别技术目前已经非常成熟,识别率也越来越高.人脸识别技术与其他生物特征识别技术相吃比,在实际应用中具有天然独到的优势:通过摄像头直接获取,可以非接触的方式完成识别过程,方便快捷. 目前已应用在金融 ...

  5. 人脸识别APP技术开发

    人脸识别技术目前已经非常成熟,识别率也越来越高.人脸识别技术与其他生物特征识别技术相吃比,在实际应用中具有天然独到的优势:通过摄像头直接获取,可以非接触的方式完成识别过程,方便快捷. 目前已应用在金融 ...

  6. 人脸识别App面临的安全风险

    中国信通院:2020年人脸识别技术在App应用中的隐私安全研究报告 节选 人脸识别App面临的安全风险 人脸识别技术应用在提升身份认证便捷度和效率的同时,也给个人隐私和数据保护带来了巨大的挑战.通过评 ...

  7. 人脸识别系统中的活体检测技术有哪些分类

    人脸识别系统在实际应用中会面对照片.视频.面具等道具攻击,为了这防止这些欺诈手段,在系统中应用到活体检测,检测识别的人员是否为活体,提高应用的安全性.由畅视智能与你分享应用到人脸识别系统中的活体检测技 ...

  8. 云栖大会人脸识别闸机【技术亮点篇3】--人脸识别闸机摆闸可达500万次

    云栖大会人脸识别闸机[技术亮点篇3]–人脸识别闸机摆闸可达500万次 人脸识别检票闸机,已经开始广泛的应用在全国各大展览会.会议等人员进出通道场所,依照其外观类型也叫翼闸人脸识别闸机.检测报告中显示: ...

  9. 云栖大会人脸识别闸机【技术亮点篇6】--人脸识别闸机采用活体检测技术

    云栖大会人脸识别闸机[技术亮点篇6]–人脸识别闸机采用活体检测技术 云栖大会使用的人脸识别闸机采用了活体检测技术,而为云栖大会提供闸机硬件的艾力奋会展服务公司的人脸识别系统中,也采用了活体检测技术.活 ...

最新文章

  1. discuz 修改积分策略( 在周期中添加每周 )
  2. __cpuidex读取CPU序列号
  3. fft重叠帧_关于FFT实时频谱的几个基本概念 | 科创仪表局
  4. linux mysql移植_linux 下mysql 移植设置方法
  5. jfinal 源码中文乱码解决
  6. iOS 静态库,动态库与 Framework 浅析
  7. mysql 求差函数_mysql 数学函数
  8. 《数据结构与面向对象程序设计》第二、三周学习总结
  9. flutter TabBar设置圆角背景
  10. 手机HTML5 audio 无法自动播放下一首
  11. 做电商,怎么降低快递运输成本?
  12. 使用阿里的easyexcel 导入xls类型Excel文件报错问题深挖
  13. 舞钢大业投资王恒:央行再度定向降准力挺“三农”小微覆盖大部分的城市商业银行
  14. Awesome Adb——一份超全超详细的 ADB 用法大全【转】
  15. 危化品爆炸场景下的应急通信系统解决方案
  16. 前端需要了解的5G网络知识
  17. linux添加javahome
  18. 教你使用shell脚本打印五角星
  19. 个人日记-学习究竟是什么读后感3-2020/7/13
  20. Delete数据如何恢复

热门文章

  1. 拼多多怎么做?无货源新手怎么轻松上手?(小珏)
  2. Python进制转换与ASCII转换
  3. HDU 4489 The King’s Ups and Downs(组合DP)
  4. 软件设计师 软考 真题练习 (二)
  5. 猿创征文|我命由我,不由天
  6. origin画图对图片进行缩放时,如何不让文字一同缩放?
  7. 2017年计算机二级考试的word的答案,2017年3月全国计算机考试等级考试二级《MS Office高级应用》真题及答案...
  8. 软谋在线教育推荐好书(一)
  9. MTK MT6771处理器,helio P60芯片参考资料
  10. 在线考试系统的时间控制(倒计时)