美文网首页
微信人脸核身后台接口开发记录

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

作者: 一介书生独醉江湖 | 来源:发表于2022-04-29 13:35 被阅读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;
        }
    

    相关文章

      网友评论

          本文标题:微信人脸核身后台接口开发记录

          本文链接:https://www.haomeiwen.com/subject/mlcsyrtx.html