微信小程序实现人脸识别认证

微信小程序实现人脸识别认证

这个项目中使用的是阿里云的实人认证接口,需要录制视频上传

先说一下逻辑:

1、获取摄像头和录音权限;
2、调起摄像头用于录制视频,录制5s;
3、录制结束后上传视频;
4、取上传返回的视频地址,调用后端提供的人脸识别接口,判断视频中是否含有人脸;
5、通过人脸识别后会返回一个图片地址,调用后端提供的实人认证接口
6、若这个过程中出现错误,则重新录制上传,本项目中失败三次则提示认证失败,可重新识别

上代码:
wxml:

<view class='identification'>
  <view class='camera' wx:if="{{ showCamera }}">
    <camera device-position="front" flash="off" binderror="error"></camera>
  </view>
</view>
<view class='message' wx:if="{{msgStatus == 0}}">
  <text>将脸对准圆框内,即可自动扫描识别</text>
  <view wx:if="{{ recordStatus == 0 }}">准备开始录像</view>
  <view wx:elif="{{ recordStatus == 1 }}">{{countDownNum}}s</view>
  <view wx:else>录制结束</view>
</view>
<view class='message' wx:if="{{msgStatus == 1}}">
  <image src='{{host}}user/msgsuccess.png' mode='widthFix'></image>
  <view class='msgTitle'>认证成功</view>
  <view class='msgContent'>感谢您对我们的信任</view>
  <navigator open-type='switchTab' url='/pages/index/index' class='nextBtn'>进入首页</navigator>
</view>
<view class='message' wx:if="{{msgStatus == -1}}">
  <image src='{{host}}user/msgerror.png' mode='widthFix'></image>
  <view class='msgTitle'>认证失败</view>
  <view bindtap='rescan' class='nextBtn'>重新扫描</view>
</view>

wxss

.identification {
  width: 480rpx;
  height: 480rpx;
  margin-top: 10%;
  margin-left: 50%;
  transform: translate(-50%, 0);
}

.identification .camera {
  width: 430rpx;
  height: 430rpx;
  position: absolute;
  top: 20rpx;
  left: 20rpx;
}

.identification .camera .zz {
  width: 100%;
  height: 100%;
  position: absolute;
  top: 0;
  overflow: hidden;
}

.identification .camera camera {
  width: 100%;
  height: 100%;
}

.message {
  text-align: center;
  margin-top: 60rpx;
}

.message text {
  font: 24rpx/50rpx "";
  color: #333;
  display: flex;
  justify-content: center;
}

.message view {
  font: 46rpx/50rpx "";
  color: #4877D1;
  display: flex;
  justify-content: center;
  margin-top: 40rpx;
}

.message view.msgTitle {
  font: 32rpx/50rpx "";
  color: #333;
  display: flex;
  justify-content: center;
  margin-top: 20rpx;
}

.message view.msgContent {
  font: 24rpx/50rpx "";
  color: #999;
  display: flex;
  justify-content: center;
  margin-top: 20rpx;
}

.message image {
  width: 70rpx;
  height: 70rpx;
}

.message .nextBtn {
  width: 400rpx;
  margin: 40rpx auto 0;
  background: #4877D1;
  color: #fff;
  font: 32rpx/80rpx "";
  border-radius: 50rpx;
}

.crl-dot {
  width: 10rpx;
  height: 10rpx;
  background: red;
  position: absolute;
  top: -10rpx;
  left: -10rpx;
}

js

const app = getApp()
Page({

  /**
   * 页面的初始数据
   */
  data: {
    countDownNum: 5, // 录制视频时间
    msgStatus: 0, // 识别状态,0为未识别或识别中,1为识别成功,-1为识别失败
    i: '',
    recordNum: 0, // 记录识别次数
    showCamera: false, // 是否显示相机
    recordStatus: 0 // 录制状态,0为未开始录制, 1为开始录制,2为结束录制
  },

  onLoad() {
    this.getAuthorize('scope.camera', 1)
  },
  getAuthorize: function(value, num) { // 判断是否授权摄像头和录音,num表示判断的序号,1为摄像头,2为录音
    let _this = this
    wx.getSetting({
      success: res => {
        console.log(res.authSetting)
        if (res.authSetting[value] != true) {
          wx.authorize({
            scope: value,
            success () {
              _this.successNext(num)
            }, fail() {
              console.log('未授权');
              wx.showModal({
                title: '开启' + (num == 1 ? '摄像机' : '录音') + '失败',
                showCancel: false,
                content: '点击确定重试!',
                success: function (res) {
                  if (res.confirm) {
                    _this.openSetting(value, num)
                  }
                }
              });
            }
          })
        } else { // 权限开启成功
          _this.successNext(num)
        }
      }
    })
  },
  openSetting: function(value, num) { // 打开设置页
    var _this =this;
    wx.openSetting({
      success(res) {
        if (res.authSetting[value] != true){
          wx.showModal({
            title: '开启' + (num == 1 ? '摄像机' : '录音') + '失败',
            showCancel: false,
            content: '点击确定重试!',
            success: function (res) {
              if (res.confirm) {
                _this.openSetting(value, num)
              }
            }
          });
        } else {
          _this.successNext(num)
        }
      }, fail(res) {
        console.log(res)
      }
    })
  },
  successNext: function(num) {
    if (num == 1) { // 摄像头权限获取成功,去获取录音权限
      this.getAuthorize('scope.record', 2)
    } else if (num == 2) { // 录音权限获取成功,开始录像
      this.openCamera();
      console.log('已授权');
    }
  },
  openCamera: function() { // 打开相机
    this.setData({
      showCamera: true
    })
    this.ctx = wx.createCameraContext();
    this.countDown();
  },

  countDown: function (e) { // 视频录制三秒
    let that = this;
    let countDownNum = 5; // 获取倒计时初始值
    let i = this.data.i;
    if (!i) {
      i = 2
    }
    that.data.recordNum++;
    that.setData({
      recordStatus: 1,
      timer: setInterval(function () {
        if (countDownNum == 5) {
          that.startRecord(); // 开始录制
        }
        countDownNum--;
        that.setData({
          countDownNum: countDownNum,
          i: i
        })
        if (countDownNum == 0) {
          clearInterval(that.data.timer); // 清空定时器
          that.stopRecord(); // 结束录制
        }
      }, 1000)
    })
  },


  startRecord() { // 开始录制
    var _this = this;
    _this.ctx.startRecord({
      success: (res) => {
        console.log('录像开始')
      },fail(res){
        console.log('录像未开始')
      }
    })
  },
  stopRecord() {
    var that = this;
    console.log('停止录像');
    that.ctx.stopRecord({
      success: (res) => {
        that.setData({
          recordStatus: 2
        })
        that.uploadFile(res)
      },fail(res){
        console.log(res);
        that.judgeStatus()
      }
    })
  },
  judgeStatus: function() { // 失败时判断是否继续识别
    var that = this;
    if (that.data.recordNum < 3 && that.data.msgStatus != 1) {
      setTimeout(function () {
        that.setData({
          countDownNum: 5
        })
        that.countDown();
      }, 1000)
    } else if (that.data.recordNum == 3 && that.data.msgStatus != 1) {
      that.setData({
        countDownNum: 5,
        msgStatus: -1
      })
    }
  },

  uploadFile: function(file) { // 上传视频
    var that = this;
    wx.showLoading({
      title: '视频上传中',
    })
    wx.uploadFile({
      url: 'http://图片上传接口地址',
      filePath: file.tempThumbPath,
      name: 'img', // 上传的视频字段名
      success: function (res) {
        console.log(res);
        wx.hideLoading()
        if (res.code == '00000') { // 上传成功
          that.identify(res.data.img)
        } else {
          that.judgeStatus()
        }
      }, fail(res) {
        wx.hideLoading()
        wx.showToast({
          title: '视频上传失败',
        })
        that.judgeStatus()
      }
    })
  },

  identify: function(img) { // 请求后端人脸识别接口
    wx.showLoading({
      title: '正在识别',
    })
    wx.request({
      url: 'http://人脸识别接口地址', // 判断是否有人脸
      data: {
        image: img
      },
      method: "POST",
      success: function (res) {
         console.log(res)
        if (res.data.code == '00000') {
          console.log('人脸识别成功');
          var image_url = res.data.data.image_url;
          wx.request({
            url: 'http://实人认证接口地址', // 实人认证
            data: {
              image_url: res.data.data.image_url
            },
            method: "POST",
            success: function (res) {
              console.log('实人认证成功');
              wx.hideLoading();
              if (res.data.code == '00000') {
                that.setData({
                  msgStatus: 1
                })
                // 实人认证成功后的操作
              } else {
                wx.hideLoading();
                console.log('实人认证失败');
                that.judgeStatus()
              }
            }
          })
        } else {
          console.log('人脸识别失败' + that.data.recordNum);
          wx.hideLoading();
          that.judgeStatus()
        }
      }
    })
  },

  // 重新扫描
  rescan: function () {
    this.onLoad();
    this.setData({
      msgStatus: 0,
      recordNum: 0,
      recordStatus: 0
    })
  },

  onUnload: function () {
    var that = this;
    clearInterval(that.data.timer);
  },
})
  • 4
    点赞
  • 39
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
要在 Java 中对接微信小程序支付,你需要完成以下步骤: 1. 获取微信支付的 API 密钥和商户号,以及小程序 appID 和 appSecret。 2. 在小程序开发者工具中创建支付统一下单接口,并记录好接口地址。 3. 在 Java 中编写代码,向微信支付下单接口发送请求,并获取返回的 prepay_id。 4. 将 prepay_id 和其他参数按照微信支付要求的格式进行签名,并返回给前端。 5. 前端通过微信小程序支付 API 调起支付界面,用户完成支付后,微信服务器会向商户服务器发送支付结果通知。 6. 商户服务器接收到支付结果通知后,需要进行签名验证和订单处理。 以下是一份示例代码,可以帮助你完成微信小程序支付的对接: ```java import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.util.HashMap; import java.util.Map; import java.util.SortedMap; import java.util.TreeMap; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import org.w3c.dom.Document; import org.w3c.dom.Element; public class WechatPayment { private String appid; // 小程序 ID private String mch_id; // 商户号 private String key; // API 密钥 public WechatPayment(String appid, String mch_id, String key) { this.appid = appid; this.mch_id = mch_id; this.key = key; } public Map<String, String> unifiedorder(String body, String out_trade_no, int total_fee, String spbill_create_ip, String notify_url) throws Exception { SortedMap<String, String> params = new TreeMap<String, String>(); params.put("appid", appid); params.put("mch_id", mch_id); params.put("nonce_str", getRandomString(32)); params.put("body", body); params.put("out_trade_no", out_trade_no); params.put("total_fee", String.valueOf(total_fee)); params.put("spbill_create_ip", spbill_create_ip); params.put("notify_url", notify_url); params.put("trade_type", "JSAPI"); params.put("openid", "用户的 openid"); String sign = createSign(params); params.put("sign", sign); String xml = mapToXml(params); String responseXml = HttpUtils.post("https://api.mch.weixin.qq.com/pay/unifiedorder", xml); DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); DocumentBuilder builder = factory.newDocumentBuilder(); Document document = builder.parse(new ByteArrayInputStream(responseXml.getBytes())); Element rootElement = document.getDocumentElement(); String return_code = getElementValue(rootElement, "return_code"); String result_code = getElementValue(rootElement, "result_code"); String prepay_id = getElementValue(rootElement, "prepay_id"); if ("SUCCESS".equals(return_code) && "SUCCESS".equals(result_code) && prepay_id != null) { Map<String, String> result = new HashMap<String, String>(); result.put("prepay_id", prepay_id); String nonce_str = getRandomString(32); result.put("nonceStr", nonce_str); result.put("timeStamp", String.valueOf(System.currentTimeMillis() / 1000)); result.put("signType", "MD5"); result.put("package", "prepay_id=" + prepay_id); sign = createSign(result); result.put("paySign", sign); return result; } else { throw new Exception(getElementValue(rootElement, "return_msg")); } } private String createSign(Map<String, String> params) throws NoSuchAlgorithmException { StringBuilder sb = new StringBuilder(); for (Map.Entry<String, String> entry : params.entrySet()) { if (entry.getValue() != null && entry.getValue().length() > 0 && !"sign".equals(entry.getKey()) && !"key".equals(entry.getKey())) { sb.append(entry.getKey()).append("=").append(entry.getValue()).append("&"); } } sb.append("key=").append(key); MessageDigest md = MessageDigest.getInstance("MD5"); md.update(sb.toString().getBytes()); byte[] digest = md.digest(); StringBuilder signBuilder = new StringBuilder(); for (byte b : digest) { String hex = Integer.toHexString(b & 0xff); if (hex.length() == 1) { signBuilder.append("0"); } signBuilder.append(hex); } return signBuilder.toString().toUpperCase(); } private String mapToXml(Map<String, String> params) { StringBuilder sb = new StringBuilder(); sb.append("<xml>"); for (Map.Entry<String, String> entry : params.entrySet()) { sb.append("<").append(entry.getKey()).append(">"); sb.append(entry.getValue()); sb.append("</").append(entry.getKey()).append(">"); } sb.append("</xml>"); return sb.toString(); } private String getElementValue(Element element, String tagName) { Element childElement = (Element) element.getElementsByTagName(tagName).item(0); if (childElement != null) { return childElement.getTextContent(); } return null; } private String getRandomString(int length) { String str = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"; StringBuilder sb = new StringBuilder(); for (int i = 0; i < length; i++) { sb.append(str.charAt((int) (Math.random() * str.length()))); } return sb.toString(); } } ``` 其中,HttpUtils.post() 方法用于发送 HTTP POST 请求,你需要自己实现。在 unifiedorder() 方法中,我们按照微信支付要求的格式构造请求参数,并对参数进行签名。然后向微信支付下单接口发送请求,获取 prepay_id。最后,我们将 prepay_id 和其他参数按照微信支付要求的格式进行签名,并返回给前端。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值