接入腾讯云直播笔记--人脸核身篇

303 阅读2分钟

公司有直播的需求,选择了对接腾讯的sdk(吐槽一下,腾讯的文档写得是真的垃圾,但是功能倒是挺全的)


人脸核身: 用户首次使用时需要申请直播的开播权限,腾讯刚好有人脸核身的服务,需要在腾讯平台申请信息

由于我们使用的是appsdk 所以需要看的是appsdk 增强版的文档

大概流程是需要由服务端生成并下发参数,客户端获取参数后启动sdk,进行人脸核身,sdk返回人脸核身结果,服务端验证人脸结果

代码:

人脸核身sdk的信息,也就是申请sdk时的信息


@Component

@ConfigurationProperties(prefix = "tencent-faceid")

public class TencentFaceIdInfo {

    // 腾讯人脸核身的访问api

    private String bizTokenUrl;

    //腾讯人脸核身sdkwbappid

    private String WBappid;

    //腾讯人脸核身sdk Secret

    private String secret;

    private String keyLicense;

}

Nacos 上的配置

人脸核身工具类

/**
* @author hzl
* 人脸核身
*/
@Component
@Slf4j
public class TencentFaceIdClient {
    @Resource
    private TencentFaceIdInfo tencentFaceIdInfo;
    @Resource
    private TencentLiveInfo tencentLiveInfo;

    private static String ACCESS_TOKEN_URL = "https://miniprogram-kyc.tencentcloudapi.com/api/oauth2/access_token";
    private static String TICKET_URL = "https://miniprogram-kyc.tencentcloudapi.com/api/oauth2/api_ticket";
    private static String SUCCESS = "0";
        


/**
* 获取accessToken
* @return
* @throws Exception
*/
    public String getAccessToken() throws Exception {
        HashMap<String,Object> paramMap = new HashMap<>();
        paramMap.put("app_id",tencentFaceIdInfo.getWBappid());
        paramMap.put("secret",tencentFaceIdInfo.getSecret());
        paramMap.put("grant_type","client_credential");
        paramMap.put("version","1.0.0");
        String result = HttpUtil.get(ACCESS_TOKEN_URL, paramMap);
        JSONObject object = JSONObject.parseObject(result);
        String code = object.getString("code");
        if (!SUCCESS.equals(code)){
            throw new BizException("请求AccessToken失败");
        }
        return object.getString("access_token");
    }

        /**
        * 获取SignTicket
        * @return
        * @throws Exception
        */
    public String getSignTicket(String accessToken) throws Exception {
        HashMap<String,Object> paramMap = new HashMap<>();
        paramMap.put("app_id",tencentFaceIdInfo.getWBappid());
        paramMap.put("access_token",accessToken);
        paramMap.put("type","SIGN");
        paramMap.put("version","1.0.0");
        String result = HttpUtil.get(TICKET_URL, paramMap);
        JSONObject object = JSONObject.parseObject(result);
        String code = object.getString("code");
        if (!SUCCESS.equals(code)){
            throw new BizException("请求SignTicket失败");
        }
        return object.getJSONArray("tickets").getJSONObject(0).getString("value");
    }

   
        /**
        * 获取ApiTicket
        * @return
        * @throws Exception
        */

    public String getApiTicket(String accessToken,String userId) throws Exception {
        HashMap<String,Object> paramMap = new HashMap<>();
        paramMap.put("app_id",tencentFaceIdInfo.getWBappid());
        paramMap.put("access_token",accessToken);
        paramMap.put("type","NONCE");
        paramMap.put("version","1.0.0");
        paramMap.put("user_id",userId);
        String result = HttpUtil.get(TICKET_URL, paramMap);
        JSONObject object = JSONObject.parseObject(result);
        String code = object.getString("code");
        if (!SUCCESS.equals(code)){
            throw new BizException(“请求ApiTicket失败");
         }
        return object.getJSONArray("tickets").getJSONObject(0).getString("value");
    
    }

        /**
        * 生成签名
        * @param values
        * @param ticket
        * @return
        */
    public static String sign(List<String> values, String ticket) {
        if (values == null) {
            throw new NullPointerException("values is null");
        }
        values.removeAll(Collections.singleton(null));
        values.add(ticket);
        java.util.Collections.sort(values);
        StringBuilder sb = new StringBuilder();
        for (String s : values) {
            sb.append(s);
        }
        return Hashing.sha1().hashString(sb, Charsets.UTF_8).toString().toUpperCase();
    }

/**
* 获取签名
* @param
* @param ticket
* @return
*/
    public String getSign(String wbappid,String userId,String version,String ticket,String nonce){
        List<String> values = new ArrayList<String>();
        values.add(wbappid);
        values.add(userId);
        values.add(version);
        values.add(nonce);
        String sign = sign(values, ticket);
        return sign;
    }



    public String getFaceId(FaceIdReq req){
//        Map<String, Object> paramMap = BeanUtil.beanToMap(req);
        String paramStr = JSONObject.toJSONString(req);
        HttpResponse response = HttpUtil.createPost("https://miniprogram-kyc.tencentcloudapi.com/api/server/getfaceid")
                .body(paramStr).contentType("application/json").execute();
        String responseBody = response.body();
        JSONObject object = JSONObject.parseObject(responseBody);
        String code = object.getString("code");
        if (!SUCCESS.equals(code)){
            throw new BizException("请求faceId失败");
        }
        String faceId = object.getJSONObject("result").getString("faceId");
        return faceId;
    }

    public FaceIdResult getFaceIdResult(String appId,String version,String nonce,String orderNo,String sign,String getFile){
        HashMap<String, Object> map = new HashMap<>();
        map.put("app_id",appId);
        map.put("version","1.0.0");
        map.put("nonce",nonce);
        map.put("sign",sign);
        map.put("order_no",orderNo);
        map.put("get_file",getFile);
        String resp = HttpUtil.get("https://miniprogram-kyc.tencentcloudapi.com/api/server/sync", map);
        log.info("身份认证结果{}",resp);
        JSONObject object = JSONObject.parseObject(resp);
        String code = object.getString("code");
        if (!SUCCESS.equals(code)){
            log.info("请求身份认证查询失败 code:"+code);
            FaceIdResult faceIdResult = new FaceIdResult();
            faceIdResult.setResult(false);
            return faceIdResult;
        }
        FaceIdResult result = object.getObject("result", FaceIdResult.class);
        result.setResult(true);
        return result;
    }



    public static String getRandomNumByLength(int length) {
        String base = "ABCDEFGHIJKMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890";
        Random random = new Random();
        StringBuffer sb = new StringBuffer();
        for ( int i = 0; i < length; i++ ){
            int number = random.nextInt( base.length() );
            sb.append( base.charAt( number ) );
        }
        return sb.toString();
    }

    public String getRandomNumByLength(Integer randomNumLength, String type){
        String rNum = String.valueOf(System.currentTimeMillis());
        Integer typeLength = type.length();
        int i = randomNumLength - rNum.length()-typeLength;
        String nonceStr = type+rNum+ getRandomNumByLength(i);
        return nonceStr;
    }



}

Controller (服务端接口)

@PostMapping("face-init-sdk")
public R<FaceIdSdkInitResp> faceInitSdk(@RequestBody @Valid FaceInitReq faceInitReq){
    return faceIdAuthService.faceInitSdk(faceInitReq);
}

service (接口实现)

@Override
@Transactional(rollbackFor = Exception.class)
public R<FaceIdSdkInitResp> faceInitSdk(FaceInitReq req) {
    String order = client.getRandomNumByLength(16, "ORDER");
    //记录用户认证的信息
    try {
        //获取缓存中的信息
        String token = redisService.getString(RedisKeyUtil.getFaceAccessToken());
        String signTicketKey = RedisKeyUtil.getSignTicket(token);
        String signTicket = redisService.getString(signTicketKey);
        if (Objects.isNull(signTicket)){
            //重新获取,并存入缓存
            token = client.getAccessToken();
            signTicket = client.getSignTicket(token);
            redisService.setString(RedisKeyUtil.getFaceAccessToken(), token, RedisConstant.ACCESS_TOKEN_TIME_OUT);
            String ticketKey = RedisKeyUtil.getSignTicket(token);
            redisService.setString(ticketKey,signTicket);
        }
        String nonce = client.getRandomNumByLength(32, "NONCE");
        String nonceTicket = client.getApiTicket(token, String.valueOf(req.getUserId()));
        String sign = client.getSign(faceIdInfo.getWBappid(), String.valueOf(req.getUserId()), "1.0.0", signTicket,nonce);
        String apiSign = client.getSign(faceIdInfo.getWBappid(), String.valueOf(req.getUserId()), "1.0.0", nonceTicket, nonce);
        FaceIdReq faceIdReq = new FaceIdReq();
        faceIdReq.setWebankAppId(faceIdInfo.getWBappid());
        faceIdReq.setOrderNo(order);
        faceIdReq.setName(req.getUserName());
        faceIdReq.setIdNo(req.getIdCard());
        faceIdReq.setUserId(String.valueOf(req.getUserId()));
        faceIdReq.setSign(sign);
        faceIdReq.setNonce(nonce);
        String faceId = client.getFaceId(faceIdReq);
        FaceIdSdkInitResp resp = new FaceIdSdkInitResp();
        resp.setFaceId(faceId);
        resp.setAgreementNo(order);
        resp.setOpenApiAppId(faceIdInfo.getWBappid());
        resp.setOpenApiNonce(nonce);
        resp.setOpenApiUserId(String.valueOf(req.getUserId()));
        resp.setOpenApiSign(apiSign);
        resp.setKeyLicence(faceIdInfo.getKeyLicense());
        return R.ok(resp);
    } catch (Exception e) {
       throw new BizException(e.getMessage());
    }
}

请求参数

@Data
public class FaceInitReq extends BaseRequest {

    @NotNull
    private String userName;
    @NotNull
    private String IdCard;
    @NotNull
    private Long userId;
}

服务端获取人脸结果

String token = redisService.getString(RedisKeyUtil.getFaceAccessToken());
String signTicketKey = RedisKeyUtil.getSignTicket(token);
String signTicket = redisService.getString(signTicketKey);
if (Objects.isNull(signTicket)){
    //重新获取,并存入缓存
    token = client.getAccessToken();
    signTicket = client.getSignTicket(token);
    redisService.setString(RedisKeyUtil.getFaceAccessToken(), token, RedisConstant.ACCESS_TOKEN_TIME_OUT);
    String ticketKey = RedisKeyUtil.getSignTicket(token);
    redisService.setString(ticketKey,signTicket);
}
String nonce = client.getRandomNumByLength(32, "NONCE");
String sign = client.getSign(faceIdInfo.getWBappid(), faceIdResultReq.getOrderId(), "1.0.0", signTicket,nonce);
FaceIdResult faceIdResult = client.getFaceIdResult(faceIdInfo.getWBappid(), "1.0.0", nonce,faceIdResultReq.getOrderId(), sign, "0");

以上就是接入腾讯人脸核身的大概流程