文章目录
人脸识别,使用官方API:腾讯云人脸核身之独立H5接入。接口官方返回code = 0 表示成功,其他code码值均为对应码值信息,详见错误码。
注意:
1.合作方上送身份信息的计算签名参数与启动人脸核身计算签名参数不一致,有部分区别。
2.wbappid = webankAppId = app_id
前端入参:客户身份证号、客户姓名、用户 ID (userId)、from(App || browser)
controller
@Autowired
private PCH5SendIdentityService pch5SendIdentityService;
/**
* 合作方后台上送身份信息 PC H5
* 文档:https://cloud.tencent.com/document/product/1007/35893
* <p>
* 请求 URL:https://miniprogram-kyc.tencentcloudapi.com/api/server/h5/geth5faceid?orderNo=xxx
* 请求方法:POST
* 报文格式:Content-Type: application/json
* </p>
*
* @param faceDetectUserVO 身份信息
*/
@PostMapping("/sendH5IdentityInfoUserInfo")
public TXH5IdentityInfoDTO sendH5IdentityInfoUserInfo(@RequestBody FaceDetectUserVO faceDetectUserVO) {
return pch5SendIdentityService.sendH5IdentityInfoUserInfo(faceDetectUserVO);
}
entity
@Data
@AllArgsConstructor
@NoArgsConstructor
public class FaceDetectUserVO {
// https://cloud.tencent.com/document/product/1007/35893
private String name;//姓名
private String idNo;//证件号码
private String userId;//用户 ID ,用户的唯一标识(不能带有特殊字符),需要跟生成签名的 userId 保持一致
private String from;//来源 App || browser)
}
后端固定参数:wbappid = webankAppId = app_id(API中介绍命名不同,注意)、orderNo(可自定义随机生成不唯一)、userId(可自定义随机生成不唯一)、version
https://cloud.tencent.com/document/product/1007/57603
/**
* 获取 access_token
* 文档: https://cloud.tencent.com/document/product/1007/37304
*
* @return
*/
@Override
public String getAccessTokenTencent() {
// 从redis中获取accessTokenTencent
String accessTokenTencent = redisUtils.get("accessTokenTencent");
log.info("获取redis中的accessToken,为:[{}]", accessTokenTencent);
if (StringUtils.isEmpty(accessTokenTencent)) {
String accessTokenUrl = String.format(TencentCloudConfig.ACCESS_TOKEN_URL, appId, secret);
String jsonStr = HttpUtil.doGet(accessTokenUrl, null);
log.info("返回报文;->{}", jsonStr);
Map<String, String> jsonMap = ConvertUtils.stringToMap(jsonStr);
if (!"0".equals(jsonMap.get("code"))) {
String msg = jsonMap.get("msg");
log.error("获取腾讯token信息错误,code:{},msg:{}", jsonMap.get("code"), msg);
GraceJSONResult.errorMsg(msg);
/**
* 错误响应示例:
* {
* "code": "66660000",
* "msg": "请求参数异常",
* "bizSeqNo": "22090720001184453210262184859700",
* "transactionTime": "20220907102621",
* "success": false,
* "expire_in": 0
* }
*/
}
/**
* 正确响应示例:
* {
* "code":"0","msg":"请求成功",
* "transactionTime":"20151022043831",
* "access_token":"accessToken_string",
* "expire_time":"20151022043831",
* "expire_in":"7200"
* }
*/
// 获取 access_token
accessTokenTencent = jsonMap.get("access_token");
// 过期时间 默认7200L 设置6800L提前重新获取
redisUtils.set("accessTokenTencent", accessTokenTencent, 6800L);
}
log.info("返回有效accessToken,为:[{}]", accessTokenTencent);
return accessTokenTencent;
}
https://cloud.tencent.com/document/product/1007/57613
通过token获取signTicket
/**
* 获取 SIGN ticket
* 请求地址: http://localhost:9900/getSignTicketTencent
* 文档: https://cloud.tencent.com/document/product/1007/37305
*
* @param accessTokenTencent access_token
* @return
*/
@Override
public String getSignTicketTencent(String accessTokenTencent) {
// 从redis中获取nonceTicketTencent
String signTicketTencent = redisUtils.get("signTicketTencent");
log.info("获取redis中的signTicketTencent,为:[{}]", signTicketTencent);
String signTicketValue = null;
if (StringUtils.isEmpty(signTicketTencent)) {
String getSignTicketUrl = String.format(TencentCloudConfig.SIGN_TICKET_URL, appId, accessTokenTencent);
String jsonStr = HttpUtil.doGet(getSignTicketUrl, null);
log.info("返回报文;->{}", jsonStr);
TicketDTO ticketDTO = JSON.parseObject(jsonStr, TicketDTO.class);
if (!"0".equals(ticketDTO.getCode())) {
String msg = ticketDTO.getMsg();
log.error("获取腾讯signTicket信息错误,code:{},msg:{}", ticketDTO.getCode(), msg);
GraceJSONResult.errorMsg(msg);
}
/**
* 正确响应示例:
* {
* "code": "0",
* "msg": "请求成功",
* "transactionTime": "20151022044027",
* "tickets": [
* {
* "value": "ticket_string",
* "expire_in": "3600",
* "expire_time": "20151022044027"
* }
* ]
* }
*/
signTicketValue = ticketDTO.getTickets().get(0).getValue();
// 过期时间 默认3600L 设置3200L提前重新获取
redisUtils.set("signTicketTencent", signTicketValue, 3000L);
}
return signTicketValue;
}
计算合作方上送身份信息签名,参数有:wbappid、orderNo、name、idNo、userId、version、signTicket

计算签名
/**
* PC 端 H5 接入 > 合作方上送身份信息计算签名
* 文档地址:https://cloud.tencent.com/document/product/1007/35893
*
* @param faceDetectUserVO
* @param signTicket
* @return
*/
public String signH5(FaceDetectUserVO faceDetectUserVO, String signTicket) {
//为计算签名做准备
//为计算签名做准备
List<String> list = new ArrayList<>();
list.add(appId);
list.add(faceDetectUserVO.getOrderNo());
list.add(faceDetectUserVO.getName());
list.add(faceDetectUserVO.getIdNo());
list.add(faceDetectUserVO.getUserId());
list.add(TencentCloudConfig.VERSION);
return SignUtils.getSign(list, signTicket);
}
/**
* 合作方后台上送身份信息 PC H5
* 文档:https://cloud.tencent.com/document/product/1007/35893
* <p>
* 请求 URL:https://miniprogram-kyc.tencentcloudapi.com/api/server/h5/geth5faceid?orderNo=xxx
* 请求方法:POST
* 报文格式:Content-Type: application/json
* </p>
*
* @param faceDetectUserVO 身份信息
* @return
*/
@Override
public TXH5IdentityInfoDTO sendH5IdentityInfoUserInfo(FaceDetectUserVO faceDetectUserVO) {
//获取accessToken
String accessToken = commonIdentityService.getAccessTokenTencent();
//获取signTicket
String signTicket = commonIdentityService.getSignTicketTencent(accessToken);
//订单号
String orderNo = SignUtils.GenerateRandom32Number(32);
faceDetectUserVO.setOrderNo(orderNo);
//合作方上送计算签名
String sign = signH5(faceDetectUserVO, signTicket);
Map<String, String> param = new HashMap<>(16);
param.put("webankAppId", appId);
param.put("orderNo", orderNo);
param.put("name", faceDetectUserVO.getName());
param.put("idNo", faceDetectUserVO.getIdNo());
param.put("userId", faceDetectUserVO.getUserId());
param.put("version", TencentCloudConfig.VERSION);
param.put("sign", sign);
log.debug("合作方上送身份信息参数有:[{}]", param);
String getFaceidUrl = String.format(TencentCloudConfig.GET_H5_FACEID_URL, orderNo);
String jsonStr = HttpUtil.doPost(getFaceidUrl, JSON.toJSONString(param));
log.info("返回报文;->{}", jsonStr);
TXH5IdentityInfoDTO txh5IdentityInfoDTO = JSON.parseObject(jsonStr, TXH5IdentityInfoDTO.class);
log.info("合作方上送身份信息接口返回:[{}]", txh5IdentityInfoDTO);
return txh5IdentityInfoDTO;
}
在合作方成功上送身份信息后,可以获取到h5faceId
(32位随机数)
获取nonceTicket(通过token & userId)
https://cloud.tencent.com/document/product/1007/61074
计算启动H5人脸核身签名,参数有:wbappid、orderNo、userId、version、h5faceId、nonce、nonceTicket

/**
* 启用 H5 人脸认证 人脸核身计算签名
* 文档:https://cloud.tencent.com/document/product/1007/35894
*
* @param orderNo 订单号,字母/数字组成的字符串,本次人脸验证合作伙伴上送的订单号,唯一标识
* @param userId 用户 ID ,用户的唯一标识(不要带有特殊字符)
* @param nonceTicket 合作伙伴服务端实时获取的 tikcet,注意是 NONCE 类型
* @param h5faceId h5/geth5faceid 接口返回的唯一标识
* @param nonce 随机数:32位随机串(字母+数字组成的随机数)
* @return
*/
private String faceSignH5(String orderNo, String userId, String nonceTicket, String h5faceId, String nonce) {
//为计算签名做准备
List<String> list = new ArrayList<>();
list.add(appId);
list.add(orderNo);
list.add(userId);
list.add(TencentCloudConfig.VERSION);
list.add(h5faceId);
list.add(nonce);
String sign = SignUtils.getSign(list, nonceTicket);
log.info("启动人脸核身返回签名为:[{}]", sign);
return sign;
}
将成功拉起人脸核身验证通过后的回调页面链接配置至配置文件,同时对该链接进行encode编码
获取到所有拉起人脸核身所需参数后,向链接https://ida.webank.com/api/web/login拼接上参数:webankAppId、version、nonce、orderNo、h5faceId、url、sign、from、userId。例如:
https://ida.webank.com/api/web/login?webankAppId=%s&version=1.0.0&nonce=%s&orderNo=%s&h5faceId=%s&url&userId=%s&sign=%s&from=%s
接好后,直接将该链接返回前端去打开即可拉起人脸核身。请注意,该链接仅一次有效!!!
/**
* 构造人脸核身获取启动链接
* 文档:https://cloud.tencent.com/document/product/1007/35894
*
* @param faceDetectUserVO
* @return
*/
@Override
public GraceJSONResult startCheckFace(FaceDetectUserVO faceDetectUserVO) {
//随机生成32位唯一用户ID和订单ID
String userId = SignUtils.GenerateRandom32Number(32);
String orderNo = SignUtils.GenerateRandom32Number(32);
faceDetectUserVO.setOrderNo(orderNo);
faceDetectUserVO.setUserId(userId);
String requestUrl = "";
try {
//获取accessToken
String accessToken = commonIdentityService.getAccessTokenTencent();
//上送合作方用户信息
TXH5IdentityInfoDTO txh5IdentityInfoDTO = sendH5IdentityInfoUserInfo(faceDetectUserVO);
if (!"0".equals(txh5IdentityInfoDTO.getCode())) {
String msg = txh5IdentityInfoDTO.getMsg();
log.info("启动人脸核身--上送合作方用户信息异常,异常原因为:[{}]]", msg);
GraceJSONResult.errorMsg(msg);
}
//获取h5/geth5faceid 接口返回的唯一标识
String h5faceId = txh5IdentityInfoDTO.getResult().getH5faceId();
//获取32位随机数
String nonce = SignUtils.GenerateRandom32Number(32);
//获取nonceTicket
String nonceTicket = commonIdentityService.getNonceTicketTencent(accessToken, userId);
//启动人脸核身计算签名
String sign = faceSignH5(orderNo, userId, nonceTicket, h5faceId, nonce);
//成功拉起人脸识别并识别成功或失败后的回调路径
String oauthCallback = TencentCloudConfig.OAUTH_CALLBACK_URL;
log.debug("人脸核身通过后的回调地址-拼接路径加密前:url = [{}]", oauthCallback);
String oauthRedirectUrl = URLEncoder.encode(oauthCallback, "utf-8");
log.debug("人脸核身通过后的回调地址-拼接路径加密后:url = [{}]", oauthRedirectUrl);
/**
* https://miniprogram-kyc.tencentcloudapi.com/api/pc/login?webankAppId=appId001
* &version=1.0.0
* &nonce=4bu6a5nv9t678m2t9je5819q46y9hf93
* &orderNo=161709188560917432576916585
* &h5faceId=wb04f10695c3651ce155fea7070b74c9
* &url=https%3a%2f%2fcloud.tencent.com
* &userId=23333333333333
* &sign=5DD4184F4FB26B7B9F6DC3D7D2AB3319E5F7415F
*/
requestUrl = String.format(TencentCloudConfig.REQUEST_URL, appId, nonce, orderNo, h5faceId, oauthRedirectUrl, userId, sign, faceDetectUserVO.getFrom());
} catch (Exception e) {
log.error("启动人脸核身异常,异常原因为:[{}]", e.getMessage());
}
log.info("启动人脸核身--请求路径为:[{}]]", requestUrl);
return GraceJSONResult.ok(requestUrl);
}


/**
* 前端获取结果验证签名
* API:https://cloud.tencent.com/document/product/1007/61302
*
* @param orderNo 订单号,字母/数字组成的字符串,本次人脸核身合作伙伴上送的订单号,唯一标识
* @return
*/
private String getCheckSign(String orderNo) {
//获取accessToken
String accessToken = commonIdentityService.getAccessTokenTencent();
//获取signTicket
String signTicket = commonIdentityService.getSignTicketTencent(accessToken);
List list = new ArrayList<>();
list.add(appId);
list.add(orderNo);
list.add(TencentCloudConfig.VERSION);
list.add(SignUtils.GenerateRandom32Number(32));
String sign = SignUtils.getSign(list, signTicket);
log.info("前端获取结果验证签名值为\"[{}]", sign);
return sign;
}
我有一个在Linux服务器上运行的ruby脚本。它不使用rails或任何东西。它基本上是一个命令行ruby脚本,可以像这样传递参数:./ruby_script.rbarg1arg2如何将参数抽象到配置文件(例如yaml文件或其他文件)中?您能否举例说明如何做到这一点?提前谢谢你。 最佳答案 首先,您可以运行一个写入YAML配置文件的独立脚本:require"yaml"File.write("path_to_yaml_file",[arg1,arg2].to_yaml)然后,在您的应用中阅读它:require"yaml"arg
目录1.AdmobSDK下载地址2.将下载好的unityPackagesdk导入到unity里编辑 3.解析依赖到项目中
说在前面这部分我本来是合为一篇来写的,因为目的是一样的,都是通过独立按键来控制LED闪灭本质上是起到开关的作用,即调用函数和中断函数。但是写一篇太累了,我还是决定分为两篇写,这篇是调用函数篇。在本篇中你主要看到这些东西!!!1.调用函数的方法(主要讲语法和格式)2.独立按键如何控制LED亮灭3.程序中的一些细节(软件消抖等)1.调用函数的方法思路还是比较清晰地,就是通过按下按键来控制LED闪灭,即每按下一次,LED取反一次。重要的是,把按键与LED联系在一起。我打算用K1来作为开关,看了一下开发板原理图,K1连接的是单片机的P31口,当按下K1时,P31是与GND相连的,也就是说,当我按下去时
技术选型1,前端小程序原生MINA框架cssJavaScriptWxml2,管理后台云开发Cms内容管理系统web网页3,数据后台小程序云开发云函数云开发数据库(基于MongoDB)云存储4,人脸识别算法基于百度智能云实现人脸识别一,用户端效果图预览老规矩我们先来看效果图,如果效果图符合你的需求,就继续往下看,如果不符合你的需求,可以跳过。1-1,登录注册页可以看到登录页有注册入口,注册页如下我们的注册,需要管理员审核,审核通过后才可以正常登录使用小程序1-2,个人中心页登录成功以后,我们会进入个人中心页我们在个人中心页可以注册人脸,因为我们做人脸识别签到,需要先注册人脸才可以进行人脸比对,进
我在标准rails2.1项目中使用Test/Unit。我希望能够独立于任何特定的Controller/操作来测试分部View。好像ZenTest'sTest::Rails::ViewTestCase会有所帮助,但我无法让它工作,与view_testhttp://www.continuousthinking.com/tags/view_test类似Google出现的大部分内容似乎都已经过时了,所以我猜它并不真正适用于Rails2.1非常感谢任何帮助。谢谢,罗兰 最佳答案 我们正在使用RSpec在我们的Rails2.1项目中,我们可以做
我正在编写一个可配置的Rails引擎。我有一个authentication_helper配置选项来定义在所有需要身份验证的Controller的before_action中应该调用哪个助手。问题是我无法从引擎的Controller访问父应用程序的助手。Myunderstanding是因为引擎是隔离的。我考虑过使用block而不是方法名称,但我不确定这是否可行,或者我是否能够从我的Controller外部干净地访问授权逻辑。ActiveAdmin,我过去用过,有一个类似的配置选项。我注意到他们的引擎不是隔离的,所以我可能高估了引擎隔离的重要性?有没有一种优雅的方式既可以享受引擎隔离的好处
本文章承接《基于Python的人脸识别课堂考勤系统(毕设)》,填坑上篇文章遗留的代码部分。因为项目分的模块比较多,再加上本人能力有限,所以代码过于臃肿还存在许多优化的地方。同样本篇文章也仅适用于小白,零基础人群。PS:每个文件之中代码都已经区分开来,可以对照左侧目录部分实现快速预览! 由于代码过于多我这里分成上,下两个部分来发布吧!一、主文件importosimportsysimportrandomimportpymysqlimportcv2importnumpyasnpfrommathimportpifrommatplotlibimportpyplotaspltfromPILimpor
三大公有云厂商,香港地区主机测评一、ping时延比对(厦门电信本地测试):Ping时延测试腾讯云阿里云华为云延迟率最低时延44ms,最高72ms,平均46ms47.242段:最低时延59ms,最高204ms,平均107ms最低时延45ms,最高93ms,平均47ms丢包率丢包率小有的ip段丢包率较大每个段都会有概率丢包阿里云:47.242段:最低时延59ms,最高204ms,平均107ms,有的ip段丢包率较大8.210段:最低时延64ms,最高232ms,平均119ms,丢包率较好腾讯云:最低时延44ms,最高72ms,平均46ms,丢包率小华为云:最低时延45ms,最高93ms,平均47m
文章目录前言1.AI的发展历程2.我是如何接触到人工智能的概念和产品的3.对于ChatGPT的一点看法4.AI对大学毕业生的职业发展的利与弊5.对于AI的思考和问题前言随着ChatGPT的爆火,生成式AI,大模型的人工智能被越来越多的人注意到,同时他也带来了许多问题。本文将对几方面进行探讨。1.AI的发展历程远古时期在公元前第一个千禧年,中国,印度和希腊哲学家都提出了一些推理的研究理论,比如亚里士多德(Aristotle)进行了演绎推理三段论的完整分析,欧几里得(Euclid)所著Elements是一种形式推理的模型,MuḥammadibnMūsāal-Khwārizmī,发明了代数学,即我们
目录1古彝文与古典保护2古文识别的挑战2.1西文与汉文OCR2.2古彝文识别难点3合合信息:古彝文保护新思路3.1图像矫正3.2图像增强3.3语义理解3.4工程技巧4总结1古彝文与古典保护彝文指的是云南、贵州、四川等地的彝族人使用的文字,区别于现代意义上的彝文,古彝文指的是在民间流通使用的原生态彝文,多达87046字。古彝文的起源距今至少数千年,是世界上最古老的文字之一。对古彝文字集研究有助于理解尚未被翻译成汉文、用字尚未规范化的古籍,更深层、透彻地作用于传统文化保护。古彝文字义对照图(网络资料+邵文苑供图)古籍是不可再生的宝贵资源,应当得到妥善保护。中国的古籍在历史上迭经水火兵燹等自然灾害、