• 名词解释
  • 前端接入
    • web端
      • 兼容性
      • 引入初始化SDK JS
      • 配置验证对象
      • winWidth窗口宽度配置
      • lang配置(可选)
      • Demo
      • 接入成功样例
  • 后端接入
    • 接口名称
    • 接口地址
    • 请求
    • 请求参数
    • 支持的语言及请求示例
    • Java请求示例
    • C#请求示例
    • PHP请求示例
    • Python请求示例
  • 补充说明:
    • 1、签名计算方法
    • 2、响应码释义
    • 前端相关响应码
      • verify接口响应码释义
      • get接口响应码释义
    • 后端相关响应码
      • 响应参数
      • 二次验证接口响应码释义

    如对接入流程存在疑问,参见快速开始

    名词解释

    术语描述
    验证码业务idcaptchaId(appId), 验证码唯一标识,公开可见,用于区分不同的验证码使用场景,如登录、投票、发帖等。可在云片用户后台验证服务产品管理页面进行创建管理。
    密钥对idSecret Id, 请求密钥id,与Secret Key配对使用,用于对二次校验接口参数进行签名计算。
    密钥对KeySecret Key, 请求密钥Key, 与密钥id配对使用,用于对二次校验接口参数进行签名计算。
    验证用户拖动/点击一次验证码拼图即视为一次“验证”,不论拖动/点击是否正确。
    二次校验验证数据随表单提交到产品后台后,产品后台需要将验证数据发送到云片验证服务后台做二次校验,目的是核实验证数据的有效性。
    验证码类型滑动拼图、文字点选等,在云片用户后台产品管理页面可以创建并修改

    前端接入

    web端

    兼容性

    支持Chrome、IE9+、360、腾讯、搜狗、Safari、Firefox、Opera;主流手机浏览器

    引入初始化SDK JS

    1. <script src="https://www.yunpian.com/static/official/js/libs/riddler-sdk-0.2.2.js"></script>

    注:IE9+需要在SDK之前额外引入polyfill,示例如下

    1. <script src="https://cdn.bootcss.com/babel-polyfill/7.4.3/polyfill.min.js"></script>

    配置验证对象

    new YpRiddler(options)options对象为配置对象,以下为配置参数:

    参数类型必填备注
    onSuccessfunction(validInfo:object, close:function)Y监听验证成功事件。validInfo:验证成功返回参数(token,authenticate);close:关闭验证窗口
    appIdstringY应用标识。captchaId
    versionstringY接口版本号
    containerHTMLElementY验证逻辑绑定的元素
    noButtonbooleanF是否在container内渲染按钮,当mode不为flat时有效
    modestringFUI接入方式。flat-直接嵌入,float-浮动,dialog-对话框,external-外置滑动(拖动滑块时才浮现验证图片,仅适用于滑动拼图验证) 默认dialog
    onErrorfunctionF验证异常处理器。即当云片验证服务出现异常时,可以在此回调上处理,比如,不使用验证,或者,使用图片验证服务等。
    onFailfunction(code:int, msg:string, retry:function)F用户验证失败处理器, code: 错误码,msg: 错误信息,retry: 重试验证逻辑。默认实现为重新验证一次。
    beforeStartfunction(next:function)F进入验证逻辑前的勾子。next: 继续执行后续逻辑
    expiredintF请求过期时限。单位秒,默认30
    jsonpFieldstringFjsonp处理器名。默认为ypjsonp
    rsaPublicKeystringF加密公钥。如非异常情况则无需设置
    hostsstringF验证服务器地址。如非异常情况则无需设置
    winWidthnumber/stringF窗口宽度。宽度最小230px: 两种方式:1. 纯数字格式,单位px. 默认500; 2. 百分比格式, 比如80%,表示相对当前浏览器可视区域宽度的百分比。不小于230px
    langstringF支持语言,默认简体中文。zh-cn(简体中文)、en(英文)
    langPackobjectF外部导入所需设置语言文案。需按指定格式设置对象导入,当外部导入语言包时,lang设置会自动失效

    winWidth窗口宽度配置

    1. // 设置窗口宽度为固定值(px)
    2. new YpRiddler({
    3. ...
    4. winWidth: '500'
    5. ...
    6. })
    7. // 设置窗口宽度为屏幕宽度的百分比(窗口宽度winWidth = 屏幕宽度 * %)
    8. new YpRiddler({
    9. ...
    10. winWidth: '30%'
    11. ...
    12. })

    lang配置(可选)

    系统默认支持中文,如需要替换其他语言请进行如下配置。目前支持的语言有:简体中文、英文。如果需要设置文案的语言,可通过外部文件,按指定格式设置文案内容,然后在options配置项中通过langPack传入语言对象(object)即可。

    1. // 语言模版
    2. const LANG_OTHER = {
    3. 'YPcaptcha_01': '请点击按钮开始验证',
    4. 'YPcaptcha_02': '请按顺序点击:',
    5. 'YPcaptcha_03': '向右拖动滑块填充拼图',
    6. 'YPcaptcha_04': '验证失败,请重试',
    7. 'YPcaptcha_05': '验证成功',
    8. 'YPcaptcha_06': '验证失败'
    9. }
    10. new YpRiddler({
    11. ...
    12. langPack: LANG_OTHER
    13. ...
    14. })

    Demo

    1. <html>
    2. <head>
    3. <!--依赖-->
    4. <script src="https://www.yunpian.com/static/official/js/libs/riddler-sdk-0.2.2.js"></script>
    5. <script>
    6. window.onload = function () {
    7. // 初始化
    8. new YpRiddler({
    9. expired: 10,
    10. mode: 'dialog',
    11. winWidth: 500,
    12. lang: 'zh-cn', // 界面语言, 目前支持: 中文简体 zh-cn, 英语 en
    13. // langPack: LANG_OTHER, // 你可以通过该参数自定义语言包, 其优先级高于lang
    14. container: document.getElementById('cbox'),
    15. appId: 'your-app-id',
    16. version: 'v1',
    17. onError: function (param) {
    18. if (param.code == 429) {
    19. alert('请求过于频繁,请稍后再试!')
    20. return
    21. }
    22. // 异常回调
    23. console.error('验证服务异常')
    24. },
    25. onSuccess: function (validInfo, close) {
    26. // 成功回调
    27. alert(`验证通过!token=${validInfo.token}, authenticate=${validInfo.authenticate}`)
    28. close()
    29. },
    30. onFail: function (code, msg, retry) {
    31. // 失败回调
    32. alert('出错啦:' + msg + ' code: ' + code)
    33. retry()
    34. },
    35. beforeStart: function (next) {
    36. console.log('验证马上开始')
    37. next()
    38. },
    39. onExit: function () {
    40. // 退出验证 (仅限dialog模式有效)
    41. console.log('退出验证')
    42. }
    43. })
    44. }
    45. </script>
    46. </head>
    47. <body>
    48. <div id="cbox"></div>
    49. </body>
    50. </html>

    接入成功样例

    前端接入完成后,通过谷歌浏览器的Network查看请求记录,verify请求会返回两个参数:authenticatetoken图片

    后端接入

    接口名称

    二次验证接口

    接口地址

    https://captcha.yunpian.com/v1/api/authenticate

    请求

    • 请求方式:POST
    • 请求类型:application/x-www-form-urlencoded

    请求参数

    参数类型必填备注
    captchaIdstringY验证产品 id
    tokenstringY前端从verfiy接口获取的token,token 作为一次验证的标志。
    authenticatestringY前端从verfiy接口验证通过后,返回的参数
    secretIdstringY验证产品密钥 id
    versionstringY版本,固定值1.0
    userstringF可选值,接入方用户标志,如担心信息泄露,可采用摘要方式给出。
    timestampstringY当前时间戳的毫秒值,如1541064141441
    noncestringY随机正整数, 在 1-99999 之间,与 timestamp 配合可以防止消息重放
    signaturestringY签名信息,见签名计算方法

    支持的语言及请求示例

    Java请求示例

    1. import java.io.IOException;
    2. import java.net.URISyntaxException;
    3. import java.util.Arrays;
    4. import java.util.HashMap;
    5. import java.util.Map;
    6. import java.util.Random;
    7. import org.apache.commons.codec.digest.DigestUtils;
    8. import org.apache.commons.httpclient.HttpClient;
    9. import org.apache.commons.httpclient.methods.PostMethod;
    10. /**
    11. * A demo for YunPian CAPTCHA authenticate API
    12. */
    13. public class AuthenticateDemo {
    14. private static String AUTH_URL = "https://captcha.yunpian.com/v1/api/authenticate";
    15. public static void main(String[] args) throws IOException, URISyntaxException {
    16. Map<String, String> paramMap = new HashMap<>();
    17. // replace the following "{example}"s with actual values
    18. paramMap.put("captchaId", "{captchaId}");
    19. paramMap.put("secretId", "{secretId}");
    20. paramMap.put("token", "{token}");
    21. paramMap.put("authenticate", "{authenticate}");
    22. paramMap.put("version", "1.0");
    23. paramMap.put("timestamp", String.valueOf(System.currentTimeMillis()));
    24. paramMap.put("nonce", String.valueOf(new Random().nextInt(99999)));
    25. paramMap.put("user", "{user}"); // user is optional
    26. String signature = genSignature("{secretKey}", paramMap);
    27. paramMap.put("signature", signature);
    28. StringBuilder sb = new StringBuilder();
    29. PostMethod postMethod = new PostMethod(AUTH_URL);
    30. postMethod.addRequestHeader("Content-Type", "application/x-www-form-urlencoded");
    31. paramMap.forEach((k, v) -> {
    32. postMethod.addParameter(k, v);
    33. });
    34. HttpClient httpClient = new HttpClient();
    35. int status = httpClient.executeMethod(postMethod);
    36. String responseBodyAsString = postMethod.getResponseBodyAsString();
    37. System.out.println(responseBodyAsString);
    38. }
    39. // generate signature
    40. private static String genSignature(String secretKey, Map<String, String> params) {
    41. String[] keys = params.keySet().toArray(new String[0]);
    42. Arrays.sort(keys);
    43. StringBuilder sb = new StringBuilder();
    44. for (String key : keys) {
    45. sb.append(key).append(params.get(key));
    46. }
    47. sb.append(secretKey);
    48. return DigestUtils.md5Hex(sb.toString());
    49. }
    50. }

    C#请求示例

    1. using System;
    2. using System.Collections.Generic;
    3. using System.IO;
    4. using System.Linq;
    5. using System.Net;
    6. using System.Security.Cryptography;
    7. using System.Text;
    8. using System.Web;
    9. namespace ConsoleApp1
    10. {
    11. /// A demo for YunPian CAPTCHA authenticate API
    12. class AuthenticateDemo
    13. {
    14. protected const string AUTH_URL = "https://captcha.yunpian.com/v1/api/authenticate";
    15. protected const string VERSION = "1.0";
    16. protected const int MAX_NONCE = 99999;
    17. static void Main(string[] args)
    18. {
    19. Dictionary<string, string> parameters = new Dictionary<string, string>();
    20. // replace the following "{example}"s with actual values!!!
    21. parameters.Add("captchaId", "{captchaId}");
    22. parameters.Add("secretId", "{secretId}");
    23. parameters.Add("token", "{token}");
    24. parameters.Add("authenticate", "{authenticate}");
    25. parameters.Add("version", VERSION);
    26. parameters.Add("timestamp", GetCurrentTimeMillis());
    27. parameters.Add("nonce", GetNonce().ToString());
    28. //parameters.Add("user", "{user}"); // user is optional
    29. // generate signature
    30. string sign = GenSignature("{secretKey}", parameters);
    31. parameters.Add("signature", sign);
    32. // authenticate
    33. string retString = PostAuthData(parameters);
    34. Console.WriteLine(retString);
    35. }
    36. // post authenticate data
    37. public static string PostAuthData(Dictionary<string, string> parameters)
    38. {
    39. StringBuilder sb = new StringBuilder();
    40. foreach (var item in parameters)
    41. {
    42. if (sb.Length > 0)
    43. sb.Append("&");
    44. sb.Append(item.Key + "=" + HttpUtility.UrlEncode(item.Value, System.Text.Encoding.UTF8));
    45. }
    46. string data = sb.ToString();
    47. HttpWebRequest request = (HttpWebRequest)WebRequest.Create(AUTH_URL);
    48. request.Timeout = 30 * 1000;
    49. request.Method = "POST";
    50. request.ContentType = "application/x-www-form-urlencoded";
    51. request.ContentLength = Encoding.UTF8.GetByteCount(data);
    52. Stream myRequestStream = request.GetRequestStream();
    53. byte[] requestBytes = System.Text.Encoding.ASCII.GetBytes(data);
    54. myRequestStream.Write(requestBytes, 0, requestBytes.Length);
    55. myRequestStream.Close();
    56. HttpWebResponse response = (HttpWebResponse)request.GetResponse();
    57. Stream myResponseStream = response.GetResponseStream();
    58. StreamReader myStreamReader = new StreamReader(myResponseStream, Encoding.GetEncoding("utf-8"));
    59. string retString = myStreamReader.ReadToEnd();
    60. myStreamReader.Close();
    61. myResponseStream.Close();
    62. return retString;
    63. }
    64. // generate signature
    65. public static String GenSignature(String secretKey, Dictionary<String, String> parameters)
    66. {
    67. parameters = parameters.OrderBy(o => o.Key).ToDictionary(o => o.Key, p => p.Value);
    68. StringBuilder builder = new StringBuilder();
    69. foreach (KeyValuePair<String, String> kv in parameters)
    70. {
    71. builder.Append(kv.Key).Append(kv.Value);
    72. }
    73. builder.Append(secretKey);
    74. String tmp = builder.ToString();
    75. MD5 md5 = new MD5CryptoServiceProvider();
    76. byte[] result = md5.ComputeHash(Encoding.UTF8.GetBytes(tmp));
    77. builder.Clear();
    78. foreach (byte b in result)
    79. {
    80. builder.Append(b.ToString("x2"));
    81. }
    82. return builder.ToString();
    83. }
    84. private static int GetNonce()
    85. {
    86. Random r = new Random();
    87. int n = r.Next(1, MAX_NONCE);
    88. return n;
    89. }
    90. private static String GetCurrentTimeMillis()
    91. {
    92. TimeSpan ts = DateTime.UtcNow - new DateTime(1970, 1, 1, 0, 0, 0, 0);
    93. return Convert.ToInt64(ts.TotalMilliseconds).ToString();
    94. }
    95. }
    96. }

    PHP请求示例

    1. <?php
    2. $params = array();
    3. $params["authenticate"] ="{authenticate}";//用户验证通过后,返回的参数
    4. $params["token"] ="{token}";//前端返回的 token
    5. $params["captchaId"] ="{captchaId}";//验证产品 id
    6. $params["secretId"] ="{secretId}";//验证产品 secretId
    7. $secretKey = "{secretKey}";//验证产品 secretKey
    8. $params["version"] = "1.0";//版本,固定值1.0
    9. $params["timestamp"] = sprintf("%d", round(microtime(true)*1000));// 当前时间戳的毫秒值,如1541064141441
    10. $params["nonce"] = sprintf("%d", rand(1,99999)); //随机正整数, 在 1-99999 之间
    11. ksort($params); // 参数排序
    12. $buff="";
    13. foreach($params as $key=>$value){
    14. $buff .=$key;
    15. $buff .=$value;
    16. }
    17. $buff .= $secretKey;
    18. //print_r($buff);
    19. $signature=md5($buff);
    20. $params["signature"] =$signature ;//签名信息,见签名计算方法
    21. $url="https://captcha.yunpian.com/v1/api/authenticate";
    22. $ch = curl_init();
    23. curl_setopt($ch, CURLOPT_URL, $url);
    24. curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
    25. /* 设置返回结果为流 */
    26. curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    27. /* 设置超时时间*/
    28. curl_setopt($ch, CURLOPT_TIMEOUT, 10);
    29. /* 设置通信方式 */
    30. curl_setopt($ch, CURLOPT_POST, 1);
    31. curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
    32. curl_setopt($ch, CURLOPT_HTTPHEADER, array('Content-Type:application/x-www-form-urlencoded'));
    33. curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($params));
    34. $result = curl_exec($ch);
    35. var_dump($result);

    Python请求示例

    1. import random
    2. import time
    3. import hashlib
    4. import requests
    5. authenticate = '{authenticate}'
    6. secretKey = '{secretKey}'
    7. token = '{token}'
    8. captchaId = '{captchaId}'
    9. secretId = '{secretId}'
    10. data = {
    11. 'authenticate': authenticate,
    12. 'captchaId': captchaId,
    13. 'nonce': str(random.randint(10000, 99999)),
    14. 'secretId': secretId,
    15. 'timestamp': str(time.time()).split('.')[0],
    16. 'token': token,
    17. 'version': '1.0'
    18. }
    19. print '%s: %s' % ('data', data)
    20. sign_str = ''
    21. items = sorted(data.items(), key=lambda d:d[0])
    22. for item in items:
    23. sign_str += '%s%s' % (item[0],item[1])
    24. sign_str += secretKey
    25. print '%s: %s' % ('sign_str', sign_str)
    26. signature = hashlib.md5(sign_str).hexdigest().lower()
    27. data['signature'] = signature
    28. print '%s: %s' % ('data', data)
    29. url = 'https://captcha.yunpian.com/v1/api/authenticate'
    30. headers = {'Content-Type': 'application/x-www-form-urlencoded'}
    31. r = requests.post(url, data=data, headers=headers)
    32. print r.text

    补充说明:

    1、签名计算方法

    • 第一步:对所有请求参数(不包括 signature 参数),按照参数名ASCII码表升序顺序排序。如:foo=1, bar=2, foo_bar=3, baz=4 排序后的顺序是 bar=2, baz=4, foo=1, foo_bar=3 。
    • 第二步:将排序好的参数名和参数值构造成字符串,格式为:key1+value1+key2+value2… 。根据上面的示例得到的构造结果为:bar2baz4foo1foo_bar3 。
    • 第三步:选择与 secretId 配对的 secretKey ,加到上一步构造好的参数字符串之后,如 secretKey=e3da918313c14ea8b25db31f01263f80 ,则最后的参数字符串为 bar2barz4foo1foo_bar3e3da918313c14ea8b25db31f01263f80。
    • 第四步:把3步骤拼装好的字符串采用 utf-8 编码,使用 MD5 算法对字符串进行摘要,计算得到 signature 参数值,将其加入到接口请求参数中即可。MD5 是128位长度的摘要算法,用16进制表示,一个十六进制的字符能表示4个位,所以签名后的字符串长度固定为32位十六进制字符。上述签名的结果为:59db908f26fb997c30b32ddb911485c2。
    1. /**
    2. * 生成签名信息
    3. * @param secretKey 产品私钥
    4. * @param params 接口请求参数名和参数值map,不包括signature参数名
    5. * @return
    6. */
    7. public static String genSignature(String secretKey, Map<String, String> params){
    8. // 1. 参数名按照ASCII码表升序排序
    9. String[] keys = params.keySet().toArray(new String[0]);
    10. Arrays.sort(keys);
    11. // 2. 按照排序拼接参数名与参数值
    12. StringBuilder sb = new StringBuilder();
    13. for (String key : keys) {
    14. sb.append(key).append(params.get(key));
    15. }
    16. // 3. 将secretKey拼接到最后
    17. sb.append(secretKey);
    18. // 4. MD5是128位长度的摘要算法,转换为十六进制之后长度为32字符
    19. return DigestUtils.md5Hex(sb.toString().getBytes("UTF-8"));
    20. }

    2、响应码释义

    前端相关响应码

    verify接口响应码释义

    响应码错误信息具体描述
    0ok验证通过
    1bad request验证请求数据缺失或格式有误
    2verify fail验证不通过
    400param_invalid请求参数错误,检查i k参数
    400captcha_id_invalidcaptchaId不存在
    429too many requests请求过于频繁,请稍后再试
    500server_error服务异常

    get接口响应码释义

    响应码错误信息具体描述
    0ok获取验证图片成功
    400param_invalid请求参数错误,检查i k参数
    400captcha_id_invalidcaptchaId不存在
    429too many requests请求过于频繁,请稍后再试
    500server_error服务异常

    后端相关响应码

    响应参数

    参数类型必填备注
    codeintY成功为0,非0为异常信息,详见下方“二次验证接口响应码释义”
    msgstringY错误描述信息

    二次验证接口响应码释义

    响应码错误信息具体描述
    0ok二次验证通过
    400validate_fail二次验证不通过
    400signature_invalid签名校验失败
    400param_invalid请求参数错误,检查i k参数
    400captcha_id_invalidcaptchaId不存在
    429too many requests请求过于频繁,请稍后再试
    500server_error服务异常