2025 活体识别+人脸认证工具类【阿里云api,需要先申请试用】

(1)获取活体检测的人脸URL地址和Token。
(2)活体检测成功后,使用Token验证人脸检测结果的一致性。
(3)对于检测结果一致的人脸照片,进行姓名、身份证号和照片的认证流程。

一、活体识别场景【打码标题可以自定义】

二、阿里云试用两款产品活体检测和人脸识别

1、选择产品试用

2、控制台复制appcode

三、工具类

**1、活体检测和人脸认证工具类:**FaceUtils

java 复制代码
import com.google.gson.Gson;
import com.google.gson.JsonObject;
import com.xiaoqiu.utils.MyTimeUtils;
import com.xiaoqiu.utils.Result;
import org.apache.http.HttpResponse;
import org.apache.http.util.EntityUtils;

import java.util.HashMap;
import java.util.Map;

/**
 * 活体检测和人脸认证工具类
 */
public class FaceUtils {
    // 常量统一放在类顶部,使用更清晰的命名
    private static final String FACE_LIVENESS_HOST = "https://smkjhtjc.market.alicloudapi.com";
    private static final String FACE_LIVENESS_TOKEN_PATH = "/h5/v4/token";
    private static final String FACE_LIVENESS_RESULT_PATH = "/h5/v4/result";
    private static final String FACE_LIVENESS_APPCODE = "624f2c6a06d142f59f2d2cf2c3033ed1";

    private static final String FACE_VERIFICATION_HOST = "https://selfiev2.market.alicloudapi.com";
    private static final String FACE_VERIFICATION_PATH = "/face/verify_selfie_idnumber";
    private static final String FACE_VERIFICATION_APPCODE = "624f2c6a06d142f59f2d2cf2c3033ed1";

    private static final Gson GSON = new Gson(); // 重用Gson实例
    private static final String AUTHORIZATION_HEADER = "Authorization";
    private static final String CONTENT_TYPE_HEADER = "Content-Type";
    private static final String APPCODE_PREFIX = "APPCODE ";
    private static final String APPLICATION_FORM_URLENCODED = "application/x-www-form-urlencoded; charset=UTF-8";

    /**
     * 获取人脸的url地址
     */
    public static Result checkFaceUrl(String name, String returnUrl) throws Exception {
        Map<String, String> headers = createCommonHeaders(FACE_LIVENESS_APPCODE);
        Map<String, String> bodys = new HashMap<>();

        // 使用更清晰的参数设置方式
        bodys.put("returnUrl", returnUrl);
        bodys.put("style", "1");
        bodys.put("actionMutex", "true");
        bodys.put("antiCameraHack", "true");
        bodys.put("foreLiveOn", "true");
        bodys.put("backLiveOn", "false");
        bodys.put("showSuccess", "true");
        bodys.put("showFail", "true");
        bodys.put("hideGuidePage", "false");
        bodys.put("title", String.format("%s的活体人脸采集(采集时间:%s)", name, MyTimeUtils.getCurrentTimeYMD()));
        bodys.put("enableH5CompatibleModel", "true");
        System.out.println("正在进行活体检测人脸链接的请求参数:" + bodys);

        HttpResponse response = HttpUtils.doPost(FACE_LIVENESS_HOST, FACE_LIVENESS_TOKEN_PATH,
                "POST", headers, new HashMap<>(), bodys);

        String responseBody = EntityUtils.toString(response.getEntity());
        System.out.println("正在进行活体检测人脸链接的请求结果:" + bodys);

        JsonObject jsonObject = GSON.fromJson(responseBody, JsonObject.class);

        int code = jsonObject.get("code").getAsInt();
        if (code == 200) {
            JsonObject data = jsonObject.get("data").getAsJsonObject();
            Map<String, String> result = new HashMap<>();
            result.put("url", data.get("url").getAsString());
            result.put("token", data.get("token").getAsString());
            return Result.success(result);
        }
        return Result.error("参数有误,联系管理员");
    }

    /**
     * 根据token获取人脸检测结果url
     */
    public static Result getFaceUrl(String token) throws Exception {
        Map<String, String> headers = createCommonHeaders(FACE_LIVENESS_APPCODE);
        Map<String, String> bodys = new HashMap<>();
        bodys.put("token", token);

        System.out.println("返回根据token获取人脸检测结果url的请求参数:" + bodys);

        HttpResponse response = HttpUtils.doPost(FACE_LIVENESS_HOST, FACE_LIVENESS_RESULT_PATH,
                "POST", headers, new HashMap<>(), bodys);

        String responseBody = EntityUtils.toString(response.getEntity());
        System.out.println("返回根据token获取人脸检测结果url的请求结果:" + bodys);
        JsonObject jsonObject = GSON.fromJson(responseBody, JsonObject.class);

        int code = jsonObject.get("code").getAsInt();
        if (code == 200) {
            JsonObject data = jsonObject.get("data").getAsJsonObject();
            int result = data.get("result").getAsInt();
            String msg = data.get("codeDesc").getAsString();

            return result == 0
                    ? Result.success(data.get("faceUrl").getAsString())
                    : Result.error(msg);
        }
        return Result.error("参数错误,联系管理员");
    }

    /**
     * 人脸认证
     */
    public static Result checkFace(FaceVo faceVo) throws Exception {
        // 参数校验提取到单独方法
        Result validationResult = validateFaceVo(faceVo);
        if (validationResult != null) {
            return validationResult;
        }
        Map<String, String> headers = createCommonHeaders(FACE_VERIFICATION_APPCODE);
        Map<String, String> bodys = new HashMap<>();

        bodys.put("name", faceVo.getName());
        bodys.put("id_number", faceVo.getIdNumber());
        bodys.put("image_url", faceVo.getImage());
        bodys.put("auto_rotate", "true");

        System.out.println("正在进行人脸认证的请求参数:" + bodys);

        HttpResponse response = HttpUtils.doPost(FACE_VERIFICATION_HOST, FACE_VERIFICATION_PATH,
                "POST", headers, new HashMap<>(), bodys);
        String responseBody = EntityUtils.toString(response.getEntity());
        System.out.println("正在进行人脸认证的请求结果:" + responseBody);
        JsonObject jsonObject = GSON.fromJson(responseBody, JsonObject.class);

        String status = jsonObject.get("status").getAsString();
        if ("OK".equals(status)) {
            int code = jsonObject.get("result_code").getAsInt();
            String msg = jsonObject.get("result_message").getAsString();

            if (code == 1001) {
                String score = jsonObject.has("score")
                        ? jsonObject.get("score").getAsString()
                        : "";
                return Result.success(msg + ",相似度:" + score);
            }
            return Result.error(msg);
        }
        return Result.error("人脸识别数据有误:识别失败");
    }

    // 创建公共头部
    private static Map<String, String> createCommonHeaders(String appCode) {
        Map<String, String> headers = new HashMap<>();
        headers.put(AUTHORIZATION_HEADER, APPCODE_PREFIX + appCode);
        headers.put(CONTENT_TYPE_HEADER, APPLICATION_FORM_URLENCODED);
        return headers;
    }


    // 验证FaceVo参数
    private static Result validateFaceVo(FaceVo faceVo) {
        if (faceVo.getName() == null || faceVo.getName().isEmpty()) {
            return Result.error("姓名不能为空");
        }
        if (faceVo.getIdNumber() == null || faceVo.getIdNumber().isEmpty()) {
            return Result.error("身份证号不能为空");
        }
        if (faceVo.getImage() == null || faceVo.getImage().isEmpty()) {
            return Result.error("图片不能为空");
        }
        if (!faceVo.getName().matches("^[\\u4e00-\\u9fa5]+$")) {
            return Result.error("姓名只能包含中文");
        }
        if (!isValidIdNumber(faceVo.getIdNumber())) {
            return Result.error("身份证号不合法");
        }
        return null;
    }

    // 验证身份证号是否合法
    public static boolean isValidIdNumber(String idNumber) {
        if (idNumber == null) {
            return false;
        }

        int length = idNumber.length();
        if (length != 15 && length != 18) {
            return false;
        }

        // 验证数字部分
        int digitLength = length == 18 ? 17 : 15;
        for (int i = 0; i < digitLength; i++) {
            if (!Character.isDigit(idNumber.charAt(i))) {
                return false;
            }
        }

        // 验证18位身份证的最后一位
        if (length == 18) {
            char lastChar = idNumber.charAt(17);
            if (!(Character.isDigit(lastChar) || lastChar == 'X' || lastChar == 'x')) {
                return false;
            }
            // 如果需要更严格的校验,可以取消下面这行的注释
            // return validateCheckDigit(idNumber);
        }

        return true;
    }


    // 18位身份证校验码验证
    private static boolean validateCheckDigit(String idNumber) {
        if (idNumber.length() != 18) return false;

        int[] weightFactors = {7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2};
        char[] checkDigits = {'1', '0', 'X', '9', '8', '7', '6', '5', '4', '3', '2'};

        int sum = 0;
        for (int i = 0; i < 17; i++) {
            sum += (idNumber.charAt(i) - '0') * weightFactors[i];
        }

        char actualCheckDigit = Character.toUpperCase(idNumber.charAt(17));
        return actualCheckDigit == checkDigits[sum % 11];
    }
}

2、人脸认证参数VO类:FaceVo

java 复制代码
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

/**
 * 人脸认证参数VO类
 */
@Data
@AllArgsConstructor
@NoArgsConstructor
public class FaceVo {
    private String name;
    private String idNumber;
    private String image;
}

3、请求接口阿里云的工具类:HttpUtils

java 复制代码
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;

import org.apache.commons.lang3.StringUtils;
import org.apache.http.HttpResponse;
import org.apache.http.NameValuePair;
import org.apache.http.client.HttpClient;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpDelete;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.methods.HttpPut;
import org.apache.http.conn.ClientConnectionManager;
import org.apache.http.conn.scheme.Scheme;
import org.apache.http.conn.scheme.SchemeRegistry;
import org.apache.http.conn.ssl.SSLSocketFactory;
import org.apache.http.entity.ByteArrayEntity;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.message.BasicNameValuePair;

public class HttpUtils {

    /**
     * get
     *
     * @param host
     * @param path
     * @param method
     * @param headers
     * @param querys
     * @return
     * @throws Exception
     */
    public static HttpResponse doGet(String host, String path, String method,
                                     Map<String, String> headers,
                                     Map<String, String> querys)
            throws Exception {
        HttpClient httpClient = wrapClient(host);

        HttpGet request = new HttpGet(buildUrl(host, path, querys));
        for (Map.Entry<String, String> e : headers.entrySet()) {
            request.addHeader(e.getKey(), e.getValue());
        }

        return httpClient.execute(request);
    }

    /**
     * post form
     *
     * @param host
     * @param path
     * @param method
     * @param headers
     * @param querys
     * @param bodys
     * @return
     * @throws Exception
     */
    public static HttpResponse doPost(String host, String path, String method,
                                      Map<String, String> headers,
                                      Map<String, String> querys,
                                      Map<String, String> bodys)
            throws Exception {
        HttpClient httpClient = wrapClient(host);

        HttpPost request = new HttpPost(buildUrl(host, path, querys));
        for (Map.Entry<String, String> e : headers.entrySet()) {
            request.addHeader(e.getKey(), e.getValue());
        }

        if (bodys != null) {
            List<NameValuePair> nameValuePairList = new ArrayList<NameValuePair>();

            for (String key : bodys.keySet()) {
                nameValuePairList.add(new BasicNameValuePair(key, bodys.get(key)));
            }
            UrlEncodedFormEntity formEntity = new UrlEncodedFormEntity(nameValuePairList, "utf-8");
            formEntity.setContentType("application/x-www-form-urlencoded; charset=UTF-8");
            request.setEntity(formEntity);
        }

        return httpClient.execute(request);
    }

    /**
     * Post String
     *
     * @param host
     * @param path
     * @param method
     * @param headers
     * @param querys
     * @param body
     * @return
     * @throws Exception
     */
    public static HttpResponse doPost(String host, String path, String method,
                                      Map<String, String> headers,
                                      Map<String, String> querys,
                                      String body)
            throws Exception {
        HttpClient httpClient = wrapClient(host);

        HttpPost request = new HttpPost(buildUrl(host, path, querys));
        for (Map.Entry<String, String> e : headers.entrySet()) {
            request.addHeader(e.getKey(), e.getValue());
        }

        if (StringUtils.isNotBlank(body)) {
            request.setEntity(new StringEntity(body, "utf-8"));
        }

        return httpClient.execute(request);
    }

    /**
     * Post stream
     *
     * @param host
     * @param path
     * @param method
     * @param headers
     * @param querys
     * @param body
     * @return
     * @throws Exception
     */
    public static HttpResponse doPost(String host, String path, String method,
                                      Map<String, String> headers,
                                      Map<String, String> querys,
                                      byte[] body)
            throws Exception {
        HttpClient httpClient = wrapClient(host);

        HttpPost request = new HttpPost(buildUrl(host, path, querys));
        for (Map.Entry<String, String> e : headers.entrySet()) {
            request.addHeader(e.getKey(), e.getValue());
        }

        if (body != null) {
            request.setEntity(new ByteArrayEntity(body));
        }

        return httpClient.execute(request);
    }

    /**
     * Put String
     * @param host
     * @param path
     * @param method
     * @param headers
     * @param querys
     * @param body
     * @return
     * @throws Exception
     */
    public static HttpResponse doPut(String host, String path, String method,
                                     Map<String, String> headers,
                                     Map<String, String> querys,
                                     String body)
            throws Exception {
        HttpClient httpClient = wrapClient(host);

        HttpPut request = new HttpPut(buildUrl(host, path, querys));
        for (Map.Entry<String, String> e : headers.entrySet()) {
            request.addHeader(e.getKey(), e.getValue());
        }

        if (StringUtils.isNotBlank(body)) {
            request.setEntity(new StringEntity(body, "utf-8"));
        }

        return httpClient.execute(request);
    }

    /**
     * Put stream
     * @param host
     * @param path
     * @param method
     * @param headers
     * @param querys
     * @param body
     * @return
     * @throws Exception
     */
    public static HttpResponse doPut(String host, String path, String method,
                                     Map<String, String> headers,
                                     Map<String, String> querys,
                                     byte[] body)
            throws Exception {
        HttpClient httpClient = wrapClient(host);

        HttpPut request = new HttpPut(buildUrl(host, path, querys));
        for (Map.Entry<String, String> e : headers.entrySet()) {
            request.addHeader(e.getKey(), e.getValue());
        }

        if (body != null) {
            request.setEntity(new ByteArrayEntity(body));
        }

        return httpClient.execute(request);
    }

    /**
     * Delete
     *
     * @param host
     * @param path
     * @param method
     * @param headers
     * @param querys
     * @return
     * @throws Exception
     */
    public static HttpResponse doDelete(String host, String path, String method,
                                        Map<String, String> headers,
                                        Map<String, String> querys)
            throws Exception {
        HttpClient httpClient = wrapClient(host);

        HttpDelete request = new HttpDelete(buildUrl(host, path, querys));
        for (Map.Entry<String, String> e : headers.entrySet()) {
            request.addHeader(e.getKey(), e.getValue());
        }

        return httpClient.execute(request);
    }

    private static String buildUrl(String host, String path, Map<String, String> querys) throws UnsupportedEncodingException {
        StringBuilder sbUrl = new StringBuilder();
        sbUrl.append(host);
        if (!StringUtils.isBlank(path)) {
            sbUrl.append(path);
        }
        if (null != querys) {
            StringBuilder sbQuery = new StringBuilder();
            for (Map.Entry<String, String> query : querys.entrySet()) {
                if (0 < sbQuery.length()) {
                    sbQuery.append("&");
                }
                if (StringUtils.isBlank(query.getKey()) && !StringUtils.isBlank(query.getValue())) {
                    sbQuery.append(query.getValue());
                }
                if (!StringUtils.isBlank(query.getKey())) {
                    sbQuery.append(query.getKey());
                    if (!StringUtils.isBlank(query.getValue())) {
                        sbQuery.append("=");
                        sbQuery.append(URLEncoder.encode(query.getValue(), "utf-8"));
                    }
                }
            }
            if (0 < sbQuery.length()) {
                sbUrl.append("?").append(sbQuery);
            }
        }

        return sbUrl.toString();
    }

    private static HttpClient wrapClient(String host) {
        HttpClient httpClient = new DefaultHttpClient();
        if (host.startsWith("https://")) {
            sslClient(httpClient);
        }

        return httpClient;
    }

    private static void sslClient(HttpClient httpClient) {
        try {
            SSLContext ctx = SSLContext.getInstance("TLS");
            X509TrustManager tm = new X509TrustManager() {
                public X509Certificate[] getAcceptedIssuers() {
                    return null;
                }
                public void checkClientTrusted(X509Certificate[] xcs, String str) {

                }
                public void checkServerTrusted(X509Certificate[] xcs, String str) {

                }
            };
            ctx.init(null, new TrustManager[] { tm }, null);
            SSLSocketFactory ssf = new SSLSocketFactory(ctx);
            ssf.setHostnameVerifier(SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);
            ClientConnectionManager ccm = httpClient.getConnectionManager();
            SchemeRegistry registry = ccm.getSchemeRegistry();
            registry.register(new Scheme("https", 443, ssf));
        } catch (KeyManagementException ex) {
            throw new RuntimeException(ex);
        } catch (NoSuchAlgorithmException ex) {
            throw new RuntimeException(ex);
        }
    }
}

4、自定义返回类型:Result

java 复制代码
import java.util.HashMap;
import java.util.Map;

/**
 * 消息返回类
 *
 * @Author: houyutong
 */
public class Result {
    /**
     * 操作成功
     */
    public static int SUCCESS = 200;
    /**
     * 系统内部错误
     */
    public static int ERROR = 201;
    private static Map map = new HashMap();
    /**
     * 状态码
     */
    private int code;
    /**
     * 提示信息
     */
    private String msg;
    /**
     * 返回数据
     */
    private Object data;

    /**
     * 操作成功
     */
    public static Result success(Object data) {
        Result result = new Result();
        result.code = SUCCESS;
        result.msg = "操作成功";
        result.data = data;
        return result;
    }

    public static Result success() {
        Result result = new Result();
        result.code = SUCCESS;
        result.msg = "操作成功";
        result.data = map;
        return result;
    }


    /**
     * 操作失败
     */
    public static Result error(String msg) {
        Result result = new Result();
        result.code = ERROR;
        result.msg = msg;
        result.data = map;
        return result;
    }

    public static Result error() {
        Result result = new Result();
        result.code = ERROR;
        result.msg = null;
        result.data = map;
        return result;
    }

    /**
     * 自定义返回
     *
     * @param code 状态码
     * @param msg  提示信息
     */
    public static Result custom(int code, String msg) {
        Result result = new Result();
        result.code = code;
        result.msg = msg;
        return result;
    }

    /**
     * 自定义返回
     *
     * @param code 状态码
     * @param msg  提示信息
     * @param data 数据
     */
    public static Result custom(int code, String msg, Object data) {
        Result result = new Result();
        result.code = code;
        result.msg = msg;
        result.data = data;
        return result;
    }

    public static Result quantity(boolean b) {
        return b ? Result.success() : Result.error();
    }

    public static Result quantity(Integer number) {
        return number > 0 ? Result.success() : Result.error();
    }


    public static int getSUCCESS() {
        return SUCCESS;
    }

    public static void setSUCCESS(int SUCCESS) {
        Result.SUCCESS = SUCCESS;
    }

    public static int getERROR() {
        return ERROR;
    }

    public static void setERROR(int ERROR) {
        Result.ERROR = ERROR;
    }

    public int getCode() {
        return code;
    }

    public void setCode(int code) {
        this.code = code;
    }

    public String getMsg() {
        return msg;
    }

    public void setMsg(String msg) {
        this.msg = msg;
    }

    public Object getData() {
        return data;
    }

    public void setData(Object data) {
        this.data = data;
    }
}

四、测试场景使用

1、活体检测人脸链接

java 复制代码
    /**活体检测人脸链接
     * 
     * @param name 姓名【*这个就是活体检测链接标题】
     * @param returnUrl 回调地址
     * @return
     * @throws Exception
     */
    @GetMapping("/checkFaceUrl/{contractId}")
    public Result checkFaceUrl(String name, String returnUrl) throws Exception {
        return FaceUtils.checkFaceUrl(name, "回调地址");
    }

2、活体检测结果人脸照片链接+人脸认证

java 复制代码
  /** 获取人脸链接,成功后直接比对人脸
     * 
     * @param token token
     * @param faceVo 人脸信息参数
     * @return
     * @throws Exception
     */
    @PostMapping("/checkFace")
    @ExcludeFromGracefulResponse
    public Result checkFace(String token,FaceVo faceVo) throws Exception {
        Result result = FaceUtils.getFaceUrl(token);
        if (result.getCode() == 200) {
            faceVo.setImage(result.getData().toString());
            return FaceUtils.checkFace(faceVo);
        }else{
            return Result.error("获取人脸链接失败");
        }
    }
相关推荐
神色自若10 小时前
AbpVnext 阿里云ssl证书多个生产环境自动更新
服务器·阿里云·ssl
TG_yunshuguoji14 小时前
阿里云轻量应用服务器与ECS对比
阿里云·云计算·云服务
钉钉开发者社区1 天前
如何在阿里云百炼中使用钉钉MCP
阿里云·钉钉·mcp
chenglin0161 天前
阿里云——应用交付与负载均衡
阿里云·云计算·负载均衡
chenglin0161 天前
阿里云——计算服务深度解析与选型
阿里云·云计算
蓝黑20202 天前
阿里云短信验证码服务
阿里云·验证码·sms
创思通信2 天前
4G模块 EC200通过MQTT协议连接到阿里云
数据库·物联网·mqtt·阿里云·at·ec200a
蓝黑20203 天前
VSCode远程连接阿里云ECS服务器
服务器·vscode·阿里云
蓝黑20204 天前
阿里云ECS服务器搭建ThinkPHP环境
服务器·阿里云·thinkphp
tanxiaomi4 天前
阿里云 OSS 前端直传实战:表单上传 + Policy 模式详解
前端·阿里云·云计算