微信人脸核身后台接口开发记录

2022-04-29  本文已影响0人  一介书生独醉江湖
本文只提供后台接口部分,不提供小程序部分
首先需要登录小程序账号在后台、接入人脸核身
微信官方文档:
https://developers.weixin.qq.com/community/business/doc/000442d352c1202bd498ecb105c00d
# 二、准备接入 (请在小程序发布后,再提交人脸核身接口申请)
# 参考上面文档中的准备接入部分,按照步骤接入即可,这里略过;
application.yml
<dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.2.60</version>
        </dependency>

        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-lang3</artifactId>
            <version>3.9</version>
        </dependency>

        <dependency>
            <groupId>cn.hutool</groupId>
            <artifactId>hutool-all</artifactId>
            <version>4.1.19</version>
        </dependency>
        
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>

        <dependency>
            <groupId>com.github.xiaoymin</groupId>
            <artifactId>knife4j-spring-boot-starter</artifactId>
            <version>1.9.6</version>
        </dependency>
# JsApi是核心类,上面的依赖是为了支持其他几个工具类的
package com.example.favoritecode.jsapi;

import cn.hutool.http.HttpUtil;
import com.alibaba.fastjson.JSONObject;
import org.apache.commons.lang3.StringUtils;

import javax.annotation.Nonnull;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.Map;

/**
 * @Author ds
 * @Date 2021-09-25
 */
public class JsApi {

    private static JsApi jsApi = new JsApi();

    public JsApi(){

    }

    public static JsApi getInstance(){
        return jsApi;
    }

    private static final String ACCESS_TOKEN_GRANT_TYPE = "client_credential";

    private static final String ACCESS_TOKEN_URL = "https://api.weixin.qq.com/cgi-bin/token";

    private static final String GET_USER_ID_KEY_URL = "https://api.weixin.qq.com/cityservice/face/identify/getuseridkey";

    private static final String GET_INFO = "https://api.weixin.qq.com/cityservice/face/identify/getinfo";

    /**
     * 获取user_id_key
     * @return
     */
    public static UserIdKeyVo getUserIdKey(String appId, String appSecret, String name , String idCard){
        String accessToken = JsApi.getAccessToken(appId, appSecret);
        if(accessToken == null) {
            System.out.println("获取user_id_key 时,access_token 为 null");
            return null;
        }
        Map<String,Object> params = new HashMap<>(8);
        params.put("name",name);
        params.put("id_card_number",idCard);
        JSONObject paramJson = new JSONObject(params);
        String result = HttpUtil.post(GET_USER_ID_KEY_URL + "?access_token=" + accessToken, paramJson.toJSONString());
        JSONObject jsonObj = JSONObject.parseObject(result);
        if(jsonObj == null){
            return null;
        }

        UserIdKeyVo userIdKeyVo = JSONObject.parseObject(jsonObj.toString(), UserIdKeyVo.class);
        System.out.println("userIdKeyVo : " + userIdKeyVo);
        return userIdKeyVo;
    }

    public static GetWxFaceInfoVo getInfo(String appId, String appSecret, String verifyResult){
        String accessToken = JsApi.getAccessToken(appId, appSecret);
        if(accessToken == null) {
            System.out.println("获取getInfo 时,access_token 为 null");
            return null;
        }
        Map<String,Object> params = new HashMap<>(8);
        params.put("verify_result",verifyResult);
        JSONObject paramJson = new JSONObject(params);
        String result = HttpUtil.post(GET_INFO + "?access_token=" + accessToken, paramJson.toJSONString());
        JSONObject jsonObj = JSONObject.parseObject(result);
        if(jsonObj == null){
            return null;
        }
        GetWxFaceInfoVo getWxFaceInfoVo = JSONObject.parseObject(jsonObj.toString(), GetWxFaceInfoVo.class);
        System.out.println("getWxFaceInfoVo : " + getWxFaceInfoVo);
        return getWxFaceInfoVo;
    }

    /**
     * 获取公众号的全局唯一接口调用凭据
     */
    public static String getAccessToken(String appId, String appSecret){
        String getAccessTokenParam = null;
        String accessToken = null;
        String wechatResult = null;

        try {
            // 拼接凭证参数
           getAccessTokenParam = "appid=" + appId + "&secret=" + appSecret + "&grant_type=" + ACCESS_TOKEN_GRANT_TYPE;
            // 获取凭证
            HttpURLReturnBean httpURLReturnBean = HttpURLUtils.sendGet(ACCESS_TOKEN_URL, getAccessTokenParam, null, null, StandardCharsets.UTF_8);
            if (httpURLReturnBean.getHttpStatusCode() != 200) {
                System.out.println("get wechat access token error. response " + httpURLReturnBean);
            }
            wechatResult = httpURLReturnBean.getResult();
        } catch (Exception e) {
            System.out.println("get wechat access token exception. " + e.getMessage());
        }
        if (StringUtils.isBlank(wechatResult)) {
            System.out.println("get wechat access token exception,  not fund response result, requeset params " + getAccessTokenParam);
        }
        // 解析微信返回消息
        Map<String, String> acessTokenResponseData = acesstoken(wechatResult);
        if (acessTokenResponseData.get("accessToken") == null) {
            return null;
        }
        accessToken = acessTokenResponseData.get("accessToken");
        System.out.println("获取公众号的全局唯一接口调用凭据 accessToken : " + accessToken);
        return accessToken;
    }

    public static Map<String, String> acesstoken(@Nonnull String jsonStr) {
        Map<String, String> map = new HashMap<>();
        JSONObject jsonObj = null;
        try {
            jsonObj = JSONObject.parseObject(jsonStr);
        } catch (Exception e) {
            System.out.println("parsing wechat jscode2session result exception. " + e.getMessage());
        }
        if (jsonObj == null) {
            // 失败
            map.put("accessToken", null);
            map.put("expiresIn", "");
            return map;
        }
        Object accessToken = jsonObj.get("access_token");
        if (accessToken == null) {
            // 失败
            map.put("accessToken", null);
            map.put("expiresIn", "");
            return map;
        }
        // 成功
        map.put("accessToken", accessToken.toString());
        map.put("expiresIn", jsonObj.getString("expires_in"));
        return map;
    }

}
package com.example.favoritecode.jsapi;

import lombok.Data;

import java.util.Date;

/**
 * @Author ds
 * @Date 2021-09-25
 */
@Data
public class GetWxFaceInfoVo {
    /**
     * 注:errcode和identify_ret同时为0,代表本次认证成功。
     */
    // 错误码, 0表示本次api调用成功
    private int errcode;
    // 本次api调用的错误信息
    private String errmsg;
    // 人脸核身最终认证结果
    private int identify_ret;
    //  认证时间
    private Date identify_time;
    //  用户读的数字(如是读数字)
    private String validate_data;
    //  用户openid
    private String openid;
    //  用于后台交户表示用户姓名、身份证的凭证
    private String user_id_key;
    //  认证结束时间
    private Date finish_time;
    //  身份证号的md5(最后一位X为大写)
    private String id_card_number_md5;
    // 姓名MD5
    private String name_utf8_md5;
}
package com.example.favoritecode.jsapi;

import java.io.Serializable;

/**
 * HttpURLUtils返回值</br>
 *
 * @author ds
 * @date 2020-03-18 17:00:22
 */
public final class HttpURLReturnBean implements Serializable {

    /**
     * @Fields serialVersionUID : serialVersionUID
     */
    private static final long serialVersionUID = 977562102461091891L;

    private int httpStatusCode;

    private String result;

    /**
     * httpStatusCode.
     *
     * @return the httpStatusCode
     */
    public int getHttpStatusCode() {
        return httpStatusCode;
    }

    /**
     * httpStatusCode.
     *
     * @param httpStatusCode the httpStatusCode to set
     */
    public void setHttpStatusCode(int httpStatusCode) {
        this.httpStatusCode = httpStatusCode;
    }

    /**
     * result.
     *
     * @return the result
     */
    public String getResult() {
        return result;
    }

    /**
     * result.
     *
     * @param result the result to set
     */
    public void setResult(String result) {
        this.result = result;
    }

    @Override
    public String toString() {
        final StringBuilder sb = new StringBuilder("HttpURLReturnBean{");
        sb.append("httpStatusCode=").append(httpStatusCode);
        sb.append(", result='").append(result).append('\'');
        sb.append('}');
        return sb.toString();
    }
}
package com.example.favoritecode.jsapi;


import com.alibaba.fastjson.util.IOUtils;
import com.sun.xml.internal.ws.util.UtilException;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.HttpURLConnection;
import java.net.URL;
import java.nio.charset.Charset;

/**
 * Http请求工具类</br>
 *
 * @author ds
 * @date 2020-03-18 17:00:22
 */
public final class HttpURLUtils {

    private static final Logger logger = LoggerFactory.getLogger(HttpURLUtils.class);

    /**
     * GET请求</br>
     *
     * @param strURL      URL字符串
     * @param param       "&"链接的键值对
     * @param token       授权token
     * @param contentType contentType
     * @param charset     StandardCharsets.xxx
     * @return HttpURLReturnBean HttpURLReturnBean
     */
    public static HttpURLReturnBean sendGet(@Nonnull String strURL, @Nullable String param,
                                            String token, String contentType, Charset charset) throws UtilException {
        logger.info("sendGet URL [{}], params [{}], token [{}], contentType[{}]", strURL, param, token, contentType);
        StringBuilder result = new StringBuilder();
        HttpURLReturnBean httpURLStatusBean = new HttpURLReturnBean();
        PrintWriter out = null;
        BufferedReader in = null;
        HttpURLConnection conn;
        try {
            URL realUrl = new URL(strURL);
            conn = (HttpURLConnection) realUrl.openConnection();
            conn.setRequestMethod("GET");
            if (StringUtils.isNotBlank(token)) {
                conn.addRequestProperty("Authorization", "Bearer " + token);
            }
            if (StringUtils.isNotBlank(contentType)) {
                conn.setRequestProperty("Content-Type", contentType);
            }
            conn.setDoInput(true);
            if (StringUtils.isNotBlank(param)) {
                conn.setDoOutput(true);
                out = new PrintWriter(conn.getOutputStream());
                out.print(param);
                out.flush();
            }
            httpURLStatusBean.setHttpStatusCode(conn.getResponseCode());
            try {
                in = new BufferedReader(new InputStreamReader(conn.getInputStream(), charset));
            } catch (Exception e) {
                in = new BufferedReader(new InputStreamReader(conn.getErrorStream(), charset));
            }
            String line;
            while ((line = in.readLine()) != null) {
                result.append(line);
            }
        } catch (Exception e) {
            System.err.println("\n****************************** HttpURLUtils.sendGet ******************************");
            System.err.println("** strURL:\t" + strURL);
            System.err.println("** param:\t" + param);
            System.err.println("** token:\t" + token);
            System.err.println("** contentType:\t" + contentType);
            System.err.println("** charset:\t" + charset);
            System.err.println("");
            logger.error("HttpURLUtils.sendGet happen exception, [{}]:", e);
            throw new UtilException("HttpURLUtils.sendGet happen exception.");
        } finally {
            IOUtils.close(out);
            IOUtils.close(in);
        }
        String resultStr = result.toString();
        logger.debug("sendGet result [{}]", resultStr);
        httpURLStatusBean.setResult(resultStr);
        return httpURLStatusBean;

    }
}

package com.example.favoritecode.jsapi;

import lombok.Data;

/**
 * @Author ds
 * @Date 2021-09-25
 */
@Data
public class UserIdKeyVo {

    //  错 误码
    private int errcode;
    //  错 误 信息
    private String errmsg;
    //  用于后台交户表示用户姓名、身份证的凭证
    private String user_id_key;
    // user_id_key 有效期,过期需重新获取
    private String expires_in;

}

import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;

/**
 * @Author ds
 * @Date 2022-04-29
 */
@Data
@ApiModel(value = "UserIdKeyReuqestVo", description = "当事人")
public class UserIdKeyReuqestVo {

    /**
     * 姓名
     */
    @ApiModelProperty(value="姓名", example="姓名", notes="姓名")
    private String name;

    /**
     * 身份证号
     */
    @ApiModelProperty(value = "身份证号", example = "15040219860826093X")
    private String idNum;


}

import lombok.Data;

import java.io.Serializable;

/**
 * @Author ds
 * @Date 2021-09-25
 */
@Data
public class GetWxFaceInfoRequestVo implements Serializable {

    private static final long serialVersionUID = 1L;

    private String verifyResult;

    private String certNo;

    private String userIdKey;

    @Override
    public String toString() {
        return "GetWxFaceInfoRequestVo{" +
                "verifyResult='" + verifyResult + '\'' +
                ", certNo='" + certNo + '\'' +
                ", userIdKey='" + userIdKey + '\'' +
                '}';
    }
}

# 具体实现的impl部分代码
@Override
    public UserIdKeyVo getUseridkey(UserIdKeyReuqestVo userIdKeyReuqestVo) {
        String wx_appid = cfgService.getValue("wx_appid");
        String wx_secret = cfgService.getValue("wx_secret");
        return JsApi.getUserIdKey(wx_appid, wx_secret, userIdKeyReuqestVo.getName(), userIdKeyReuqestVo.getIdNum());
    }

    @Override
    public GetWxFaceInfoVo getWxFaceInfo(GetWxFaceInfoRequestVo getWxFaceInfoRequestVo) {
        String wx_appid = cfgService.getValue("wx_appid");
        String wx_secret = cfgService.getValue("wx_secret");
        GetWxFaceInfoVo getWxFaceInfoVo = JsApi.getInfo(wx_appid, wx_secret, getWxFaceInfoRequestVo.getVerifyResult());
        if (getWxFaceInfoVo.getErrcode() == 0 && getWxFaceInfoVo.getIdentify_ret() == 0) {
            logger.info("微信人脸核身 - 查询人脸核身信息  核验成功 开始更新数据");
            // TODO 这里更新成功数据
        }else {
            // TODO 这里更新失败状态数据
        }
        logger.info("** 查询人脸核身信息->获取getInfo : " + JSON.toJSONString(getWxFaceInfoVo));
        return getWxFaceInfoVo;
    }
上一篇下一篇

猜你喜欢

热点阅读