金融级实人认证 H5 网页集成方式提供 Web SDK,支持在浏览器或内嵌 WebView 中完成验证。本文介绍 PC 端及移动端 H5 网页通过 iframe 接入 Web SDK 的操作流程。
浏览器兼容性说明
浏览器名称 | Android版本 | iOS版本 |
Edge | Android 4.0及以上版本 | iOS 14.3 及以上版本 |
FireFox | ||
Chrome | ||
Opera | ||
百度 | ||
Android Browser 5.0+ | ||
Safari | 不支持 | iOS 11.3 及以上版本 |
UC | Android 4.0及以上版本 | 不支持 |
UC极速浏览器 | ||
夸克浏览器 | Android 7.0 及以上版本 | 不支持 |
厂商内置浏览器 | 小米、三星等部分机型支持 | |
受制于浏览器兼容性碎片化问题,建议在流程设计上引导用户使用推荐的浏览器完成认证。
若您在手机应用App内集成该方案,可能会因为内嵌浏览器原因无法兼容,可以参考App内集成H5移动端SDK兼容性配置减少兼容性问题或集成Native SDK。
若您通过微信公众号或者小程序集成,由于微信运营审核规则的限制,可能出现无法避免的兼容性问题,建议使用纯服务端(API)接入方式。
扫脸认证
为了提升用户刷脸认证体验,URL默认自带扫脸认证引导页,用户同意认证后可以开始使用扫脸认证服务。微信公众号场景下,扫脸认证引导页是必须存在的,否则会导致摄像头无法唤起,引发黑屏现象。如需自定义UI,可参考服务端接口参数UiCustomUrl。
用户自定义 iframe 接入
若希望自行控制 iframe 容器的样式与布局,可将CertifyUrl 直接嵌入 iframe。ReturnUrl传入固定参数iframe,认证结束后通过 postMessage 发送结果。
适用场景
需要将认证区域嵌入到页面指定位置,而非全屏覆盖。
需要自定义 iframe 尺寸、边框、层级等样式。
接入流程
在代码中引入如下JS文件,并调用函数
getMetaInfo()获取MetaInfo。<script type="text/javascript" src="https://o.alicdn.com/yd-cloudauth/cloudauth-cdn/jsvm_all.js" ></script>重要调用实人认证服务端发起认证请求时,必须传入实时获取的 MetaInfo 值。
该值随浏览器和设备环境动态变化,测试阶段也需实时传入,禁止使用硬编码的测试数据,否则可能导致无法获取 CertifyUrl。
调用业务服务端初始化接口获取
CertifyUrl。服务端调用接口时,需在参数中传入:CertifyUrlStyle:"L"— 获取长链格式的认证地址。ReturnUrl:"iframe"— 页面将通过 postMessage 机制向父页面发送认证结果。// 微信小程序请求参数 { ... "CertifyUrlStyle": "L", "ReturnUrl":"iframe", ... }小程序默认的
CertifyUrl不支持 iframe 嵌入使用,需要更改 URL 路径支持。// 将 certifyUrl 中的 "/h5?" 替换为 "/h5iframe?" function replaceH5ToIframe(url) { if (url.includes('/h5?')) { return url.replace('/h5?', '/h5iframe?'); } if (url.includes('/h5') && !url.includes('/h5iframe')) { return url.replace('/h5', '/h5iframe'); } return url; }
在页面中创建 iframe 元素,并将获取到的
CertifyUrl直接赋值给src属性。<!-- CertifyUrl 示例:https://rp-proxy.antdigital.com/onex/proxy/h5?clientcfg=eyJ6... --> <iframe id="idv-iframe" src="{CertifyUrl}" allow="camera" style="width: 100%; height: 600px; border: 0;" ></iframe>监听
message事件,接收认证结果。
认证结果数据结构
认证流程结束后,子页面将通过 postMessage 机制向父页面发送认证结果。返回的数据结构如下:
{
"code": "XXXX",
"subCode": "XXXX",
"extInfo": {
"certifyId": "XXXXXX"
}
}字段 | 类型 | 说明 |
code | String | 结果码,具体信息,请参见返回code。 |
subCode | String | 子结果码,具体信息,请参见返回subCode。 |
extInfo | Object | 扩展信息。 |
extInfo.certifyId | String | 认证 ID,用于后续服务端查询。 |
完整代码说明
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width,initial-scale=1,viewport-fit=cover" />
<title>金融级实人认证</title>
<!-- 引入该JS,全局注入getMetaInfo方法 -->
<script src="https://o.alicdn.com/yd-cloudauth/cloudauth-cdn/jsvm_all.js"></script>
<style>
* {
box-sizing: border-box;
margin: 0;
padding: 0;
}
html,
body {
width: 100%;
height: 100%;
}
#idv-container {
width: 100%;
height: 100vh;
background: #fff;
}
#idv-container iframe {
width: 100%;
height: 100%;
border: 0;
}
.error {
padding: 16px;
color: #d93026;
text-align: center;
}
</style>
</head>
<body>
<div id="idv-container"></div>
<script>
(() => {
const containerElement = document.getElementById('idv-container');
let messageListener = null;
function showError(message) {
containerElement.innerHTML = `<div class="error">${message}</div>`;
}
// 将 certifyUrl 中的 "/h5?" 替换为 "/h5iframe?"
function replaceH5ToIframe(url) {
if (url.includes('/h5?')) {
return url.replace('/h5?', '/h5iframe?');
}
if (url.includes('/h5') && !url.includes('/h5iframe')) {
return url.replace('/h5', '/h5iframe');
}
return url;
}
async function initAuth() {
try {
if (!window.getMetaInfo) {
throw new Error('getMetaInfo 未注入,请检查 SDK 脚本加载');
}
const metaInfo = window.getMetaInfo();
const response = await fetch('https://你的服务端初始化接口', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
metaInfo,
certifyUrlStyle: 'L',
returnUrl: 'iframe'
})
});
if (!response.ok) {
throw new Error(`初始化接口异常: ${response.status}`);
}
const result = await response.json();
if (!result?.resultObject?.certifyUrl) {
throw new Error('未获取到 certifyUrl');
}
const certifyUrl = replaceH5ToIframe(result?.resultObject?.certifyUrl);
const allowedOrigin = new URL(certifyUrl).origin;
const iframeElement = document.createElement('iframe');
iframeElement.src = certifyUrl;
iframeElement.allow = 'camera;microphone;fullscreen';
iframeElement.setAttribute('allowusermedia', 'true');
containerElement.innerHTML = '';
containerElement.appendChild(iframeElement);
messageListener = async (event) => {
if (event.origin !== allowedOrigin) return;
const payload = typeof event.data === 'string'
? (() => { try { return JSON.parse(event.data); } catch { return null; } })()
: event.data;
if (!payload || typeof payload !== 'object' || payload.code === undefined) return;
console.log('认证回调:', payload);
window.removeEventListener('message', messageListener);
};
window.addEventListener('message', messageListener, { passive: true });
} catch (error) {
console.error('[IDV] init error:', error);
showError('认证加载失败,请刷新后重试');
}
}
window.addEventListener('beforeunload', () => {
if (messageListener) {
window.removeEventListener('message', messageListener);
}
});
initAuth();
})();
</script>
</body>
</html>页面必须通过 HTTPS 协议部署,且 iframe 必须设置
allow="camera"属性,否则将无法调用摄像头。调用
InitFaceVerify接口时,ReturnUrl参数必须设置为iframe,同时父页面需监听message事件以接收认证结果。认证结束后,系统将检测当前是否处于 iframe 环境,并校验
ReturnUrl参数是否为iframe,若条件均满足则向父页面发送认证结果。为防范盗链及数据篡改风险,建议在解析结果后向服务端发起请求以获取最终验证结果,具体操作请参见DescribeFaceVerify-获取认证详细数据。
错误码说明
返回code
错误码 | 是否计费 | 错误码文案 |
1000 | 是 | 刷脸成功。 说明 表示用户完成了刷脸过程,认证建议结果为通过。 该结果仅供参考。最终认证结果请以调用服务端 |
1001 | 否 | 系统错误。 |
1003 | 否 | 验证中断。 |
2002 | 否 | 网络错误。 |
2003 | 否 | 客户端设备时间错误。 |
2006 | 是(仅认证不通过的场景计费) | 刷脸提交认证数据失败,或刷脸验证失败。 说明 该结果仅供参考。最终认证结果请以调用服务端 |
返回subCode
错误码 | subCode | 详细描述 |
1000 | Z5050 | 人脸验证成功。 |
1001 | - | 表示系统错误。 |
1003 | Z5051 | 上传刷脸图片失败。 |
Z5052 | 数据错误或程序异常。 | |
Z5053 | 网络错误。 | |
Z5054 | 摄像头无权限或无法获取摄像头数据。 | |
Z5055 | 用户退出。 | |
Z5056 | 重试次数过多。 | |
Z5058 | 视频格式不满足要求。 | |
Z5059 | 视频中无有效人脸。 | |
Z5060 | 降级页面等待状态。用户确认完成人脸识别后,可主动调用服务端接口查询认证结果,以进入后续业务页面。 | |
2002 | - | 表示网络错误。 |
2003 | - | 表示客户端设备时间错误。 |
2006 | Z5128 | Z5128(计费):人脸识别验证失败,认证未通过。具体原因请通过服务端查询接口获取。 |
Z5052 | Z5052(不计费):客户端向服务端提交认证数据时发生异常,未进入认证流程。 |