VAPTCHA
验证流程
创建验证单元,获取
VID
和Key
。点击创建。将
https://v-cn.vaptcha.com/v3.js
引入到你的页面。将 VAPTCHA 初始化到你需要的位置,具体 web 端部署请查看:Web 客户端部署。
用户验证通过得到
token
,与表单数据一同提交到服务端。服务端得到
token
后,向 VAPTCHA 服务器验证token
的有效性,验证通过说明此次请求有效,服务端验证流程请查看:服务端二次验证。
网页部署
web 客户端部署 VAPTCHA 所需的配置和接口说明文档
环境
兼容性 IE8+(IE8 及以上)、Chrome、Firefox、Safari、Opera、主流手机浏览器、iOS 及 Android 上的内嵌 Webview
安装
准备工作:创建验证单元,获取验证单元 VID(初始化 VAPTCHA 的必填参数)。
引入前端 sdk:
x
<script src="https://v-cn.vaptcha.com/v3.js"></script>
请选择就近资源地址或者直接将v3.JS下载到本地使用
中国大陆(北京): https://v-cn.vaptcha.com/v3.js
东南亚(香港): https://v-sea1.vaptcha.com/v3.js
北美(硅谷): https://v-na.vaptcha.com/v3.js
完整实例
点击式:
x
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>VAPTCHA验证码示例-点击式</title>
<style>
.VAPTCHA-init-main {
display: table;
width: 100%;
height: 100%;
background-color: #eeeeee;
}
.VAPTCHA-init-loading {
display: table-cell;
vertical-align: middle;
text-align: center;
}
.VAPTCHA-init-loading>a {
display: inline-block;
width: 18px;
height: 18px;
border: none;
}
.VAPTCHA-init-loading .VAPTCHA-text {
font-family: sans-serif;
font-size: 12px;
color: #cccccc;
vertical-align: middle;
}
</style>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.8.0/jquery.min.js"></script>
<script src="https://v-cn.vaptcha.com/v3.js"></script>
</head>
<body>
<!-- 点击式按钮建议高度介于36px与46px -->
<div id="VAPTCHAContainer" style="width: 300px;height: 36px;">
<!-- 下面代码为预加载动画代码,仅供参考 -->
<div class="VAPTCHA-init-main">
<div class="VAPTCHA-init-loading">
<a href="/" target="_blank">
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="48px"
height="60px" viewBox="0 0 24 30"
style="enable-background: new 0 0 50 50; width: 14px; height: 14px; vertical-align: middle"
xml:space="preserve">
<rect x="0" y="9.22656" width="4" height="12.5469" fill="#CCCCCC">
<animate attributeName="height" attributeType="XML" values="5;21;5" begin="0s" dur="0.6s"
repeatCount="indefinite"></animate>
<animate attributeName="y" attributeType="XML" values="13; 5; 13" begin="0s" dur="0.6s"
repeatCount="indefinite"></animate>
</rect>
<rect x="10" y="5.22656" width="4" height="20.5469" fill="#CCCCCC">
<animate attributeName="height" attributeType="XML" values="5;21;5" begin="0.15s" dur="0.6s"
repeatCount="indefinite"></animate>
<animate attributeName="y" attributeType="XML" values="13; 5; 13" begin="0.15s" dur="0.6s"
repeatCount="indefinite"></animate>
</rect>
<rect x="20" y="8.77344" width="4" height="13.4531" fill="#CCCCCC">
<animate attributeName="height" attributeType="XML" values="5;21;5" begin="0.3s" dur="0.6s"
repeatCount="indefinite"></animate>
<animate attributeName="y" attributeType="XML" values="13; 5; 13" begin="0.3s" dur="0.6s"
repeatCount="indefinite"></animate>
</rect>
</svg>
</a>
<span class="VAPTCHA-text">Vaptcha Initializing...</span>
</div>
</div>
</div>
<script>
vaptcha({
vid: '验证单元的VID',
mode: 'click',
scene: 0,
container: '#VAPTCHAContainer',
area: 'auto',
}).then(function (VAPTCHAObj) {
// 将VAPTCHA验证实例保存到局部变量中
obj = VAPTCHAObj;
// 渲染验证组件
VAPTCHAObj.render();
// 验证成功进行后续操作
VAPTCHAObj.listen('pass', function () {
serverToken = VAPTCHAObj.getServerToken();
var data = {
server: serverToken.server,
token: serverToken.token,
}
// 点击登录向服务器端接口提交数据,以下为伪代码,仅作参考
$.post('/login', data, function (r) {
if (r.code == 200) {
console.log('登录成功')
} else {
console.log('登录失败')
// 账号或密码错误等原因导致登录失败,重置人机验证
VAPTCHAObj.reset()
}
})
})
})
</script>
</body>
</html>
加载效果图:
隐藏式:
xxxxxxxxxx
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>VAPTCHA验证码示例-隐藏式</title>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.8.0/jquery.min.js"></script>
<script src="https://v-cn.vaptcha.com/v3.js"></script>
</head>
<body>
<button id="login-button">隐藏式</button>
<script>
vaptcha({
vid: '验证单元的VID',
mode: 'invisible',
scene: 0,
area: 'auto',
}).then(function (VAPTCHAObj) {
// 将VAPTCHA验证实例保存到局部变量中
obj = VAPTCHAObj;
// 验证成功进行后续操作
VAPTCHAObj.listen('pass', function () {
serverToken = VAPTCHAObj.getServerToken();
var data = {
server: serverToken.server,
token: serverToken.token,
}
// 点击登录向服务器端接口提交数据,以下为伪代码,仅作参考
$.post('/login', data, function (r) {
if (r.code == 200) {
console.log('登录成功')
} else {
console.log('登录失败')
// 账号或密码错误等原因导致登录失败,重置人机验证
VAPTCHAObj.reset()
}
})
})
// VAPTCHA实例初始化完成后,用户点击登录按钮时执行人机验证
$('#login-button').on('click', function () {
obj.validate();
})
})
</script>
</body>
</html>
重要: 请在页面加载完成时执行初始化函数,通过按钮触发 validate()
方法,不要在按钮的点击事件中执行初始化函数,否则会导致在移动端无法正常验证。
嵌入式:
xxxxxxxxxx
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>VAPTCHA验证码示例</title>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.8.0/jquery.min.js"></script>
<script src="https://v-cn.vaptcha.com/v3.js"></script>
</head>
<body>
<div id="VAPTCHAContainer" style="width: 400px; height: 230px;"></div>
<script>
vaptcha({
vid: '验证单元的VID',
mode: 'embedded',
scene: 0,
container: '#VAPTCHAContainer',
area: 'auto',
}).then(function (VAPTCHAObj) {
// 将VAPTCHA验证实例保存到局部变量中
obj = VAPTCHAObj;
// 渲染验证组件
VAPTCHAObj.render();
// 验证成功进行后续操作
VAPTCHAObj.listen('pass', function () {
serverToken = VAPTCHAObj.getServerToken();
var data = {
server: serverToken.server,
token: serverToken.token,
}
// 点击登录向服务器端接口提交数据,以下为伪代码,仅作参考
$.post('/login', data, function (r) {
if (r.code == 200) {
console.log('登录成功')
} else {
console.log('登录失败')
// 账号或密码错误等原因导致登录失败,重置人机验证
VAPTCHAObj.reset()
}
})
})
})
</script>
</body>
</html>
配置参数
必填参数
参数名 | 类型 | 说明 |
---|---|---|
vid | 字符串 | 验证单元的VID |
mode | 字符串 | 可选值click ,invisible ,embedded |
scene | 数值 | 验证单元场景,默认 0 |
可选参数
参数名 | 类型 | 默认值 | 说明 |
---|---|---|---|
lang | 字符串 | auto | 可选值,auto ,zh-CN ,en ,zh-TW ,jp |
area | 字符串 | auto | 验证节点区域,可选值 sea(东南亚),na(北美),cn(中国大陆),auto(根据用户区域自动匹配就近节点) |
prompt | 字符串 | 请绘制图中曲线完成人机验证 | 自定义验证引导文字 |
类型参数
适用类型 | 参数名 | 类型 | 必填 | 默认值 | 说明 |
---|---|---|---|---|---|
点击式、嵌入式 | container | string或HTMLElement | 是 | 无 | 容器元素或容器元素选择器 |
点击式 | style | string | 否 | dark | 按钮样式,可选dark ,light |
点击式 | color | string | 否 | #57ABFF | 按钮颜色 |
嵌入式 | guide | bool | 否 | false | 是否在嵌入式图片底部显示操作提示文字,默认 不显示 |
API 方法
render
仅供点击式、嵌入式使用。执行初始化操作,将按钮或者图片插入到配置参数中的容器中去。示例代码如下:
xxxxxxxxxx
vaptcha({
// 配置参数省略
})
.then(function (VAPTCHAObj) {
VAPTCHAObj.render() // 渲染验证组件
})
listen
用于监听验证事件。支持的事件如下:
pass
验证通过时触发
xxxxxxxxxx
vaptcha({
// 配置参数省略
})
.then(function (VAPTCHAObj) {
VAPTCHAObj.listen('pass', function () {
// 验证成功, 进行登录操作
})
})
close
关闭验证弹窗时触发
xxxxxxxxxx
vaptcha({
// 配置参数省略
})
.then(function (VAPTCHAObj) {
VAPTCHAObj.listen('close', function () {
// 验证弹窗关闭触发
})
})
validate
仅供隐藏式使用。由开发者决定何时调用该方法进行验证,比如在表单提交时调用该方法。
使用方式:
VAPTCHA
实例初始化完成后,等到用户点击登录按钮时执行validate()
方法,执行验证,验证成功后,触发验证通过事件xxxxxxxxxx
vaptcha({
// 其他配置参数省略
type: 'invisible',
}).then(function (VAPTCHAObj) {
obj = VAPTCHAObj
VAPTCHAObj.listen('pass', function () {
// 验证成功进行后续操作
})
$('#login-button').on('click', function () {
VAPTCHAObj.validate()
})
})
getServerToken
token
的有效期为 3 分钟,验证通过后 3 分钟此接口返回空。建议用户根据token
是否为空来判断是否通过 VAPTCHA 验证。所有模式均可用,推荐使用此接口来获取验证结果。用于获取验证结果, 返回
server
,token
,由于 token 只可使用一次,所以调用getServerToken
接口获取token
后,token
将被置空。推荐的用法:
xxxxxxxxxx
var serverToken = VAPTCHAObj.getServerToken()
var data = {
username: '',
password: '',
token: serverToken.token,
server: serverToken.server,
}
if (data.token === '') {
alert('请进行人机验证')
} else {
$.post('/login', data, function (r) {})
}
renderTokenInput
如果你是以直接提交表单的方式发起请求,推荐使用此函数向表单添加 server,token 值
此函数用于向表单添加两个名为
VAPTCHA_server
,VAPTCHA_token
的input
标签,如下xxxxxxxxxx
<input name="VAPTCHA_server" value="https://*.vaptcha.net/verify" />
<input name="VAPTCHA_token" value="************" />
函数接收一个参数作为存放
input
标签的容器,默认值为参数配置中的container
容器,使用隐藏式时为必填,input
将添加到配置的容器中。示例代码:
xxxxxxxxxx
vaptcha({
container: '#VAPTCHAContainer',
// 配置参数省略
})
.then(function (VAPTCHAObj) {
VAPTCHAObj.renderTokenInput('.login-form') // 向表单中添加input标签
})
reset
所有模式均可用。VAPTCHA 重置操作,例如可在登录失败时调用。
示例代码:
xxxxxxxxxx
$.post('/login', data, function (r) {
if (r.code !== 200) {
console.log('登录失败')
_obj.reset() // 重置 VAPTCHA
}
})
iOS-HTML5 部署
DEMO下载: https://github.com/vaptcha/VAPTCHA-iOS-v3.git
注意: 请将DEMO中www文件夹内的ios.html与v3.js下载到本地,并替换为自己的资源地址.
在您的 iOS App 工程的.h 文件中,导入框架的依赖库,使用第三方组件可能会有兼容问题,请使用原生webview组件。
xxxxxxxxxx
#import <WebKit/WebKit.h>
在您(需要人机验证的地方)添加
webview
,把webview
设置为隐藏.
xxxxxxxxxx
self.webView.alpha = 0
在
webView
的configuration
中的userContentController
属性中添加 js 的messageHandler
,name
为“signal
”;
xxxxxxxxxx
[_webView.configuration.userContentController addScriptMessageHandler:self.handlerHelper name:@"signal"];
在需要使用时,把
webview
显示出来并加载业务页面和按照格式配置参数vid
、lang
xxxxxxxxxx
self.webView.alpha = 1;
// 在这里配置你的ios.html资源地址,e.g.: https://xxx.com/yyy/ios.html
[self.webView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:@"你的地址?vid=5b4d9c33a485e50410192331&scene=0&lang=zh-CN&area=cn"]]];
通过
WKScriptMessageHandler
协议回调方法 获取验证数据:
xxxxxxxxxx
- (void)userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message {
if ([message.name isEqualToString:@"signal"]) {
// 销毁webView
[_webView removeFromSuperview];
_webView = nil;
// 解析返回结果
id body = message.body;
NSLog(@"%@",body);
if ([body isKindOfClass:NSString.class]) {
NSString *jsonString = body;
NSDictionary *resultDic = [NSJSONSerialization JSONObjectWithData:[jsonString dataUsingEncoding:NSUTF8StringEncoding] options:0 error:nil];
if (resultDic) {
if ([resultDic[@"signal"] isEqualToString:@"pass"]) {
_passed = YES;
}else if ([resultDic[@"signal"] isEqualToString:@"cancel"]) {
_passed = NO;
}else if ([resultDic[@"signal"] isEqualToString:@"error"]) {
_passed = NO;
}
}
//
NSString *sinal = resultDic[@"signal"];
NSString *data = resultDic[@"data"];
//
self.alertController = [UIAlertController alertControllerWithTitle:sinal message:data preferredStyle:UIAlertControllerStyleAlert];
[self.alertController addAction:[UIAlertAction actionWithTitle:@"确定" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
}]];
[self presentViewController:self.alertController animated:YES completion:nil];
}
}
}
上面
message
的body
属性返回结果为字符串,这里的字符串参数返回了验证是否通过和用户点击关闭等信息,需要在这里实现用户验证通过、失败或者取消的后续操作,具体字段为
xxxxxxxxxx
{
"signal":"pass",
"data":{
"server":"https://*.vaptcha.net/verify",
"token":"*****"
}
}
{
"signal":"cancel",
"data":""
}
{
"signal":"error",
"data”:""
}
ios.html
xxxxxxxxxx
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>VAPTCHA验证码示例-iOS</title>
<!-- 在这里配置你的v3.js资源地址,eg: https://xxx.com/v3.js -->
<script src="/v3.js"></script>
</head>
<body>
<script>
window.VAPTCHAtimeout = setTimeout(() => {
var data = {
signal: 'error',
data: 'error',
};
window.webkit.messageHandlers.signal.postMessage(JSON.stringify(data));
}, 5 * 1000);
</script>
<script>
var qs = getQueryString();
var vobj;
if (qs != []) {
var vid = qs['vid'];
var lang = qs['lang'];
var scene = qs['scene'] || 0;
var area = qs['area'] || 'cn';
vaptcha({
vid: vid,
type: 'invisible',
lang: lang,
scene: scene,
area: area,
}).then(function (obj) {
obj.listen('pass', function () {
var data = {
signal: 'pass',
data: obj.getServerToken(),
};
window.webkit.messageHandlers.signal.postMessage(JSON.stringify(data));
});
obj.listen('close', function () {
var data = {
signal: 'cancel',
data: '',
};
window.webkit.messageHandlers.signal.postMessage(JSON.stringify(data));
});
clearTimeout(window.VAPTCHAtimeout);
obj.validate();
});
}
function getQueryString() {
var qs = location.search.substr(1), // 获取url中"?"符后的字串
args = {}, // 保存参数数据的对象
items = qs.length ? qs.split('&') : [], // 取得每一个参数项,
item = null,
len = items.length;
for (var i = 0; i < len; i++) {
item = items[i].split('=');
var name = decodeURIComponent(item[0]),
value = decodeURIComponent(item[1]);
if (name) {
args[name] = value;
}
}
return args;
}
</script>
</body>
</html>
Android-HTML5 部署
DEMO下载: https://github.com/vaptcha/VAPTCHA-Android-v3.git
注意: 请将DEMO中www文件夹内的android.html与v3.js下载到本地,并替换为自己的资源地址.
在
AndroidManifest.xml
配置文件中,设置网络连接权限的权限。
xxxxxxxxxx
<uses-permission android:name="android.permission.INTERNET" />
布局文件(需要人机验证的地方)添加
webview
,把webview
设置为隐藏(android:visibility="invisible"
),在使用时设置为显示(visible
).
xxxxxxxxxx
<FrameLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
>
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
tools:context=".MainActivity"
>
<TextView
android:id="@+id/btn"
android:layout_width="match_parent"
android:layout_height="44dp"
android:layout_marginLeft="20dp"
android:layout_marginRight="20dp"
android:background="@drawable/topcolor_22dp"
android:gravity="center"
android:text="立即登录"
android:textColor="#ffffff"
android:textSize="18dp"
/>
</RelativeLayout>
<WebView
android:id="@+id/webview"
android:visibility="invisible"
android:layout_width="match_parent"
android:layout_height="match_parent"
/>
</FrameLayout>
在
activity
文件中设置webview
xxxxxxxxxx
public class MainActivity extends AppCompatActivity implements View.OnClickListener {
private TextView btn;
private WebView webview;
public static final String PASS = "pass"; // 通过
public static final String CANCEL = "cancel"; // 取消
public static final String ERROR = "error"; // 错误
public String src;
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initView();
//设置webview
setVaptcha();
}
private void setVaptcha() {
webview.setBackgroundColor(Color.TRANSPARENT);
webview.setLayerType(WebView.LAYER_TYPE_SOFTWARE, null);
webview.getSettings().setUseWideViewPort(true);
webview.getSettings().setLoadWithOverviewMode(true);
webview.getSettings().setDomStorageEnabled(true);
webview.getSettings().setDatabaseEnabled(true);
webview.getSettings().setAppCacheEnabled(true);
webview.getSettings().setAllowFileAccess(true);
webview.getSettings().setJavaScriptCanOpenWindowsAutomatically(true);
webview.getSettings().setLoadsImagesAutomatically(true);
webview.getSettings().setCacheMode(WebSettings.LOAD_DEFAULT);
// 持久化存储cookie
CookieManager instance = CookieManager.getInstance();
// 允许使用cookie
instance.setAcceptCookie(true);
instance.setAcceptThirdPartyCookies(webview,true);
// 设置不使用默认浏览器,而直接使用WebView组件加载页面。
webview.setWebViewClient(new WebViewClient() {
public void onPageFinished(WebView view, String url) {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
CookieSyncManager.getInstance().sync();
} else {
CookieManager.getInstance().flush();
}
super.onPageFinished(view, url);
}
public boolean shouldOverrideUrlLoading(WebView view, String url) {
view.loadUrl(url);
return true;
}
});
// 设置WebView组件支持加载JavaScript。
webview.getSettings().setJavaScriptEnabled(true);
// 建立JavaScript调用Java接口的桥梁。
webview.addJavascriptInterface(new VAPTCHAInterface(), "VAPTCHAInterface");
}
protected void onDestroy() {
super.onDestroy();
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
CookieSyncManager.getInstance().sync();
} else {
CookieManager.getInstance().flush();
}
}
protected void onPause() {
super.onPause();
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
CookieSyncManager.getInstance().sync();
} else {
CookieManager.getInstance().flush();
}
}
public class VAPTCHAInterface {
public void signal(String json) {
// json格式{signal:"",data:{server:"https://*.vaptcha.net/verify",token:"****"}}
// signal: pass (通过) ; cancel(取消)
try {
final JSONObject jsonObject = new JSONObject(json);
String signal = jsonObject.getString("signal");
final String data = jsonObject.getString("data");
if (PASS.equals(signal)) { // 通过
runOnUiThread(new Runnable() {
public void run() {
Toast.makeText(MainActivity.this, "验证通过:" + data, Toast.LENGTH_SHORT).show();
webview.loadUrl("");
webview.setVisibility(View.GONE);
}
});
} else if (CANCEL.equals(signal)) { // 取消
runOnUiThread(new Runnable() {
public void run() {
Toast.makeText(MainActivity.this, "验证取消:" + data, Toast.LENGTH_SHORT).show();
webview.loadUrl("");
webview.setVisibility(View.GONE);
}
});
} else if (ERROR.equals(signal)) {
runOnUiThread(new Runnable() {
public void run() {
Toast.makeText(MainActivity.this, "错误:" + data, Toast.LENGTH_SHORT).show();
webview.loadUrl("");
webview.setVisibility(View.GONE);
}
});
} else { // 其他html页面返回的状态参数
}
} catch (JSONException e) {
e.printStackTrace();
}
}
}
private void initView() {
btn = (TextView) findViewById(R.id.btn);
btn.setOnClickListener(this);
webview = (WebView) findViewById(R.id.webview);
}
public void onClick(View v) {
switch (v.getId()) {
case R.id.btn:
// 加载业务页面。
src = "你的地址"; // 在这里配置你的android.html资源地址,e.g.: https://xxx.com/yyy/android.html
webview.loadUrl(src + "?vid=5b4d9c33a485e50410192331&scene=0&lang=zh-CN&area=cn");
webview.setVisibility(View.VISIBLE);
break;
default:
break;
}
}
}
首先调用
setVaptcha()
设置webview
,然后在需要验证的地方调用以下方法
xxxxxxxxxx
webview.setVisibility(View.VISIBLE);
src = "你的地址"; // 在这里配置你的android.html资源地址,e.g.: https://xxx.com/yyy/android.html
webview.loadUrl(src + "?vid=5b4d9c33a485e50410192331&scene=0&lang=zh-CN&area=cn");
把webview
显示出来并加载业务页面和按照格式配置参数vid
、lang
把
webview
设置为透明并关闭硬件加速
xxxxxxxxxx
webview.setBackgroundColor(Color.TRANSPARENT);
webview.setLayerType(WebView.LAYER_TYPE_SOFTWARE, null);
建立 JavaScript 调用 Java 接口的桥梁时, 传过去的参数名固定为
VAPTCHAInterface
xxxxxxxxxx
webview.addJavascriptInterface(new VAPTCHAInterface(), "VAPTCHAInterface");
public class VAPTCHAInterface {
public void signal(String json) {
}
}
在接口里面需要实现固定名字为(signal
)的方法,这里的字符串参数返回了验证是否通过和用户点击关闭等信息,需要在这里实现用户验证通过、失败或者取消的后续操作,具体字段为
xxxxxxxxxx
{
"signal":"pass",
"data":{
"server":"https://*.vaptcha.net/verify",
"token":"*****"
}
}
{
"signal":"cancel",
"data":""
}
{
"signal":"error",
"data”:""
}
android.html
xxxxxxxxxx
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>VAPTCHA验证码示例-Android</title>
<!-- 在这里配置你的v3.js资源地址,eg: https://xxx.com/v3.js -->
<script src="/v3.js"></script>
</head>
<body>
<script>
window.VAPTCHAtimeout = setTimeout(() => {
var data = {
signal: 'error',
data: 'error',
};
window.VAPTCHAInterface.signal(JSON.stringify(data));
}, 5 * 1000);
</script>
<script src="./v3.js"></script> <!-- 在这里配置你的v3.js资源地址,e.g.: https://xxx.com/v3.js -->
<script>
var qs = getQueryString();
var vobj;
if (qs != []) {
var vid = qs['vid'];
var lang = qs['lang'];
var scene = qs['scene'] || 0;
var area = qs['area'] || 'cn';
vaptcha({
vid: vid,
type: 'invisible',
lang: lang,
scene: scene,
area: area,
}).then(function (obj) {
obj.listen('pass', function () {
var data = {
signal: 'pass',
data: obj.getServerToken(),
};
window.VAPTCHAInterface.signal(JSON.stringify(data));
});
obj.listen('close', function () {
var data = {
signal: 'cancel',
data: '',
};
window.VAPTCHAInterface.signal(JSON.stringify(data));
});
clearTimeout(window.VAPTCHAtimeout);
obj.validate();
});
}
function getQueryString() {
var qs = location.search.substr(1), // 获取url中"?"符后的字串
args = {}, // 保存参数数据的对象
items = qs.length ? qs.split('&') : [], // 取得每一个参数项,
item = null,
len = items.length;
for (var i = 0; i < len; i++) {
item = items[i].split('=');
var name = decodeURIComponent(item[0]),
value = decodeURIComponent(item[1]);
if (name) {
args[name] = value;
}
}
return args;
}
</script>
</body>
</html>
插件
Discuz插件
人机验证:https://addon.dismall.com/plugins/vaptcha.html
手机注册:https://addon.dismall.com/plugins/phone_auth.html
Wordpress插件
人机验证:https://wordpress.org/plugins/vaptcha/
手机注册:https://wordpress.org/plugins/vaptcha-sms/
UniAPP插件
人机验证:https://ext.dcloud.net.cn/plugin?id=5879#detail
VUE
人机验证(vue2):https://www.vaptcha.com/document/vaptcha-vue-click.html
人机验证(vue3):https://www.vaptcha.com/document/vaptcha-vue3.html
微信小程序插件
1.添加插件
请在小程序管理后台的“设置-第三方服务-插件管理”中添加插件。搜索VAPTCHA查找插件并添加,或者直接在app.json中声明插件,填入provider: wx07ad1b2dea6b6215
,按提示添加插件。
2.获取VID及KEY
登录VAPTCHA官网,创建验证单元,免费获取VID及KEY。
详细参考验证流程
3.小程序使用
1>使用插件前,使用者要在 app.json
中声明插件,如下:
xxxxxxxxxx
app.json
{
"plugins": {
"vaptcha": {
"version": "1.0.15", // 插件版本号
"provider": "wx07ad1b2dea6b6215"
}
}
}
如上例所示,在plugins
字段中声明插件。其中,引用名(如上例中的 vaptcha
)由使用者自定义,无需和插件开发者保持一致或与开发者协调。在后续的插件使用中,该引用名将被用于表示该插件。
2>在页面.json中引入自定义组件,如下:
xxxxxxxxxx
{
"usingComponents": {
"vaptcha": "plugin://vaptcha/vaptcha"
}
}
3>在wxml页面中使用插件并在对应的js文件中监听事件
xxxxxxxxxx
页面.wxml
<vaptcha options="{{options}}" style="{{style}}" reset="{{reset}}" bind:pass="pass" bind:close="close" />
xxxxxxxxxx
页面.js
Page({
data: {
options: {
vid: '', // 填写在vaptcha官网创建的验证单元VID,必填
scene: 0 // 填写验证场景值,选填
},
style: { // 自定义按钮样式,选填
text: '单击进行人机验证', // 按钮显示文字
backgroundColor: '#00bfff' // 按钮颜色
},
reset: false // 验证成功后是否可以再次发起验证,默认为false,选填
},
pass(res) {
let serverToken = res.detail;
console.log('token:', serverToken.token);
console.log('server:', serverToken.server);
},
close() {
console.log('close');
}
})
4>可使用插槽自定义按钮(此时style不生效),如下:
xxxxxxxxxx
页面.wxml
<vaptcha options='{{options}}' bind:pass="pass" bind:close="close">
<view>单击进行人机验证</view>
</vaptcha>
后端代码部署
服务端二次验证
服务端验证的接口与返回结果说明
请求
参数名 | 参数值 | 说明 |
---|---|---|
HTTP URL | 前端人机验证成功后获取的 server 参数 | 如 https://*.vaptcha.net/verify。服务器端请增加 *.vaptcha.com 和 *.vaptcha.net 域名白名单 |
HTTP Method | POST |
请求头
参数名 | 参数值 |
---|---|
Content-Type | application/json |
请求参数
请求参数为JSON对象
参数名 | 类型 | 必填 | 说明 |
---|---|---|---|
id | String | 是 | 验证单元的VID |
secretkey | String | 是 | 验证单元的Key |
scene | Int | 是 | 配置验证单元的场景ID,e.g.0 |
token | String | 是 | 用户在前端验证成功后取得的token |
ip | String | 是 | 获取用户的remote address |
响应结果
返回json
字符串
xxxxxxxxxx
{
"success": 1, // 验证结果,1为通过,0为失败
"score": 60, // 验证得分(可信度),区间[0, 100]
"msg": "0,1,2,3" // 验证失败时为错误信息
}
当验证得分较低,或存在某些扣分项时,站长可自定义处理策略,如:让用户验证手机、邮箱等。
错误消息说明
错误消息 | 说明 |
---|---|
id empty | id 为空 |
id error | id 错误 |
scene error | 场景号错误 |
token error | token 错误 |
token expired | token 过期,token 三分钟有效期 |
frequency overrun | 超过用户自定义的验证频率上限 |
bad request | 请求错误 |
V-SMS
短信接口
V-SMS短信接口不仅有非常高的到达率,而且对价格进行了补贴,远低于市场价。
请求
参数名 | 参数值 |
---|---|
HTTP URL | http://sms.vaptcha.com/send |
HTTP Method | POST |
请求头
参数名 | 参数值 |
---|---|
Content-Type | application/json |
请求参数
请求参数为JSON对象
参数说明
参数 | 类型 | 说明 |
---|---|---|
smsid | string | 短信账户 id |
smskey | string | 短信账户 key |
token | string | VAPTCHA 验证成功返回的token,不带则没有价格补贴 |
data | string[] | 填入数据用于替换模板中的对应位置的变量 |
countrycode | string | 国别码,如:‘86’ |
phone | string | 手机号 |
templateid | string | 模板 id |
代码示例
xxxxxxxxxx
<?php
function send() {
$url = "http://sms.vaptcha.com/send";
$body = array(
'smsid' => '****',
'smskey' => '****',
'templateid' => '0',
'countrycode' => '86',
'token' => '',
'data' => ['****'], // 与模板中的 {变量} 一一对应
'phone' => '****',
);
$header = array(
"Content-type:application/json;charset='utf-8'",
"Accept:application/json"
);
$res = curl_post($url,json_encode($body),$header);
echo $res;
}
function curl_post($url,$data,$header) {
$curl = curl_init();
curl_setopt($curl, CURLOPT_URL, $url);
curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, FALSE);
curl_setopt($curl, CURLOPT_SSL_VERIFYHOST,FALSE);
curl_setopt($curl, CURLOPT_POST, 1);
curl_setopt($curl, CURLOPT_POSTFIELDS, $data);
curl_setopt($curl,CURLOPT_HTTPHEADER,$header);
curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
$output = curl_exec($curl);
curl_close($curl);
return $output;
}
?>
验证码代生成
如果你不想自己写短信验证码的校验逻辑,也可以交由 V-SMS 代为处理。
请求验证码
调用时,将对应变量替换成 "_vcode"
提交即可,如: 模板编号: 0, 短信签名: 【身份验证】, 模板内容: 验证码{变量},您正在进行{变量}身份验证,打死不要告诉别人哦! 请求参数(JSON格式):
xxxxxxxxxx
req = {
"smsid": " ",
"smskey": "****",
"token": "****",
"templateid": "0",
"countrycode":"86",
"phone": "176****0713",
"data": ["_vcode", "APP登录"]
}
校验验证码
验证码有效期为 15 分钟,有效期内同一个验证码最多允许验证 3 次,请提交如下参数进行结果校验:
接口地址:https://sms.vaptcha.com/verify
xxxxxxxxxx
req = {
"smsid" :" ", // 短信账户id
"smskey":" ", // 短信账户key
"phone" :" ", // 手机号
"vcode" :" ", // 用户提交的验证码
}
resp:{
600 验证通过
601 验证失败
}
返回码列表
返回码 | 详情 |
---|---|
200 | 成功 |
201 | 发送失败 |
202 | 用户验证失败/smskey 不正确 |
203 | 剩余短信条数不足 |
204 | 发送频率过快,换号码或稍后再试 |
205 | 短信长度受限 |
206 | 手机号码格式错误 |
207 | 验证码格式错误 |
208 | 参数错误 |
209 | 账号受限 |
210 | 国别码错误 |
211 | 模板数据错误 |
212 | 模板编号错误 |
213 | 敏感词错误 |
230 | 接口错误 |
600 | 验证通过 |
601 | 验证失败 |
设备校验
接口文档
通过 VAPTCHA 智能人机验证对用户的常用设备进行登记和校验,最多为每个用户登记 5 台设备,PC/移动端均支持。可用于免密登录、安全补充验证或站长自定义的其它场景。
注意:校验中使用的 VAPTCHA Token 需要二次验证成功后才能使用
设备查询
通过用户 ID 与 Token 查询该用户设备是否已登记,返回登录次数与最近登录时间。
请求
参数名 | 参数值 | 说明 |
---|---|---|
HTTP URL | 在前端验证成功后获取的 server 参数上追加/device | 例如:前端 server 为 https://*.vaptcha.net/verify ,最终 URL为 https://*.vaptcha.net/verify/device |
HTTP Method | GET |
请求参数
参数名 | 类型 | 必填 | 说明 |
---|---|---|---|
id | string | 是 | 用户唯一 ID,用于关联设备,无需提交用户名、手机号等隐私信息。 |
token | string | 是 | VAPTCHA 人机验证成功后获取的 Token |
响应数据:
xxxxxxxxxx
{
"code": 200,
"data": {
"id":"xxxxx", // 设备 id
"count":1, // 登录次数
"device":"Windows", // 最近登录设备
"ip":"127.0.0.1", // 最近登录ip
"latestTime":1620000000, // 最近登录时间
},
"msg": "success"
}
设备登记
为当前用户添加关联设备,最多不超过 5 台,是否登记设备可由站长决定或让 VAPTCHA 自动判断。建议仅登记经过有效身份校验的设备,比如短信/邮箱校验后再登记此设备。
请求
参数名 | 参数值 | 说明 |
---|---|---|
HTTP URL | 在前端验证成功后获取的 server 参数上追加/device | 例如:前端 server 为 https://*.vaptcha.net/verify ,最终 URL为 https://*.vaptcha.net/verify/device |
HTTP Method | PUT |
请求头
参数名 | 参数值 |
---|---|
Content-Type | application/json |
请求参数
请求参数为JSON对象
参数名 | 类型 | 必填 | 说明 |
---|---|---|---|
id | string | 是 | 登记设备时的用户 ID |
token | string | 是 | VAPTCHA 验证 Token |
regedit | int | 否 | 1 登记当前设备,0 由 VAPTCHA 自动判断是否登记 |
响应数据:
xxxxxxxxxx
{
"code": 200,
"data": {
"id":"xxxxx", // 设备 id
"count":1, // 登录次数
"device":"Windows", // 最近登录设备
"ip":"127.0.0.1", // 最近登录ip
"latestTime":1620000000, // 最近登录时间
},
"msg": "success"
}
退出设备
删除当前用户最近登录设备
请求
参数名 | 参数值 |
---|---|
HTTP URL | https://user.vaptcha.com/api/v1/device |
HTTP Method | DELETE |
请求参数
参数名 | 类型 | 必填 | 说明 |
---|---|---|---|
id | string | 是 | 登记设备时的用户 ID |
deviceId | string | 否 | 删除单条设备信息,不传值时删除用户id下的全部设备信息 |
响应数据:
xxxxxxxxxx
{
"code": 200,
"data": null,
"msg": "success"
}
查询全部设备
获取当前用户的全部登录设备
请求
参数名 | 参数值 |
---|---|
HTTP URL | https://user.vaptcha.com/api/v1/device |
HTTP Method | GET |
请求参数
参数名 | 类型 | 必填 | 说明 |
---|---|---|---|
id | string | 是 | 登记设备时的用户ID |
响应数据:
xxxxxxxxxx
{
"code": 200,
"data": [{
"id":"xxxxx", // 设备 id
"count":1, // 登录次数
"device":"Windows", // 最近登录设备
"ip":"127.0.0.1", // 最近登录ip
"latestTime":1620000000, // 最近登录时间
}],
"msg": "success"
}
常见错误
错误信息 | 描述 |
---|---|
device not found | 设备未登记或未找到此设备 |
invalid token | 无效的 VAPTCHA Token |
expired token | VAPTCHA Token 过期, Token 的有效时长为 3min |