微信小程序中实现人脸识别认证
前言
回顾2020年,最有意思的事情就是用微信小程序实现了人脸识别认证功能,期间也遇到一些问题。希望通过本文让大家了解在微信小程序中如何实现人脸识别认证功能以及如何解决遇到的问题。
一、开发准备
1、前提条件
目前微信小程序人脸识别接口(微信开放社区对其定义为 “微信人脸核身接口能力”)只对特定的主体及类目的小程序开放,详见 微信人脸核身接口能力
笔者使用的微信小程序主体类目为医疗,因此能申请该权限。
2、步骤及流程
根据 微信人脸核身接口能力文档介绍,申请接口权限的步骤及流程如下:
由于笔者使用的微信小程序已经接入了微信电子健康卡开放平台,故不用发送邮件申请,可以直接在开放平台的“小程序人脸识别申请”菜单中申请开通接口权限,如下图所示:
审核通过后,使用微信小程序账号登录微信公众平台,在“开发管理”—“接口设置”中添加人脸识别身份验证接口类目,如下图所示:
二、开始开发
1、小程序客户端
由于笔者希望在小程序的web-view组件的H5页面中调用小程序页面的人脸识别功能,故单独新建了一个页面wxfacialverify,在js的onLoad方法中接收H5传过来的参数,然后调用人脸识别接口。wxfacialverify.js代码如下:
Page({ data: { faceCheckData: {}, }, onLoad: function(options) { var that = this; that.facialRecognitionVerify(options) }, facialRecognitionVerify: function(faceCheckData) { wx.startFacialRecognitionVerify({ name: faceCheckData.name, idCardNumber: faceCheckData.idCardNumber, success(res) { var verifyResult = res.verifyResult; wx.request({ url: '/faceCheck/faceCheck.htm?action=faceIdentifyCheck', data: { 'name': faceCheckData.name, 'idCardNumber': faceCheckData.idCardNumber, 'verifyResult ': verifyResult }, header: { 'content-type': 'application/json' }, success(res) { console.log(res.data) } }) }, 'fail': function(res) { wx.showModal({ title: '提示', showCancel: false, content: "人脸识别失败!" + res.errCode + "," + res.errMsg, success: function(res) { if (res.confirm) { wx.navigateBack() } } }) } }) }, })
2、后台服务端
根据小程序传来的微信人脸识别认证结果参数进行校验并做相应的业务处理,关键java代码如下:
@RequestMapping(method = RequestMethod.POST, params = "action=faceIdentifyCheck") public String faceIdentifyCheck(HttpServletRequest request, ModelMap map) { Map < String, Object > inOutMap = new HashMap < String, Object > (); try { String name = request.getParameter("name"); String idCardNumber = request.getParameter("idCardNumber"); String verifyResult = request.getParameter("verifyResult"); String wechatCode = request.getParameter("wechatCode"); if (StringUtils.isBlank(name)) { map.put("errormsg", "name不能为空!"); return "pub/error.vm"; } if (StringUtils.isBlank(idCardNumber)) { map.put("errormsg", "idCardNumber不能为空!"); return "pub/error.vm"; } if (StringUtils.isBlank(verifyResult)) { map.put("errormsg", "verifyResult不能为空!"); return "pub/error.vm"; } String token = (String) cacheManager.get(Constants.ACCESS_TOKEN); //缓存中的token if (!StringUtils.isBlank(token)) { JSONObject resultObjectCheck = faceIdentifyCheck(verifyResult, token); if (resultObjectCheck.optInt("errcode", -1) == 0 && resultObjectCheck.optInt("identify_ret", -1) == 0) { ...... //此处代码省略,进行业务处理 map.put("errormsg", "人脸识别校验成功。"); return "pub/success.vm"; } else { map.put("errormsg", "人脸识别校验失败"); return "pub/error.vm"; } } map.put("errormsg", "token已失效!"); return "pub/error.vm"; } catch (Exception e) { logger.error("faceIdentifyCheck出现错误", e); map.put("errormsg", "出现其他错误"); return "pub/error.vm"; } } private JSONObject faceIdentifyCheck(String verifyResult, String token) { JSONObject header = new JSONObject(); header.put("Content-Type", "application/json;encoding=utf-8"); JSONObject body = new JSONObject(); body.put("verify_result", verifyResult); String retStr = HttpUtils.httpsRequestStr(WeixinConfig.faceIdentifyUrl + "?access_token=" + token, "POST", header, body.toString()); logger.info("微信小程序faceIdentify返回:{}", retStr); JSONObject resultObjectCheck = JSONObject.fromObject(retStr); return resultObjectCheck; }
三、测试运行
笔者在微信开发者工具上使用“预览”、“真机调试”功能测试微信小程序的人脸识别接口均正常,如下图所示:
四、遇到的问题
上线两天后,有工作人员反映用户在苹果手机上使用人脸识别功能的时候报错 startFacialRecognitionVerify:fail webview not ready,如下图所示:
最开始我们以为只是某个型号的苹果手机有这个问题,结果使用同事的苹果手机(iPhone 6s plus)测试发现也出现了同样的错误,不过多试几次之后却能打开人脸识别界面。
在微信开放社区搜到同样的错误,但没有解决的方法。后来又向腾讯技术人员反馈,得到的回复是其他小程序调用没问题,他们怀疑是我们调用的方式有问题。
四、解决方法
仔细检查了一下代码想了一下,觉得在页面的onLoad方法中直接调用人脸识别接口最有可能导致这个问题,因为很可能webview还没加载完。于是,在onLoad方法中只赋值,在页面单独加个按钮,点击时触发人脸识别接口。修改后的代码如下:
wxml代码如下:
< view >= "usertitle" > < div >= 'titleText' > 人脸识别认证 < /div> </view > < form bindsubmit = "facialRecognitionVerify" > < view >= 'btnToFaceCheck' > < button >= 'btnToFaceCheck' formType = "submit" > < text > 点击此处开始人脸识别认证 < /text> </button > < /view> </form >
js代码如下: onLoad: function(options) { var that = this; //页面加载调取人脸识别接口(原则上应该对options的携带的参数进行校验) that.facialRecognitionVerify(options); }