Glossary

Terminology

Description

CAPTCHA id

App id, the unique identifier of the verification code, is publicly visible. CAPTCHA Id is used to distinguish different usage scenarios, such as login, voting, posting, and the like. Creation management can be performed on the user background verification service product management page.

Secret id

The request key id.It will be used in conjunction with Secret key to perform signature calculation on the secondary parity interface parameters.

Secret key

The request Key,It will be used in conjunction with the Secret id to perform signature calculation on the secondary verification interface parameters.

Verification

Once dragging/clicking on the verification code as will be recorded a “validation” .

Secondary verification

The product background needs to send the verification data to the YunPian's service background for secondary verification, in order to verify the validity of the verification data.

CAPTCHA type

There are some types to choose: sliding puzzle, click on the picture, etc. It can be created or modified in the YunPian's user background.


Front end access


Website


Compatibility


YunPian's CAPTCHA can be used on Chrome, IE9+, 360, Tencent, Sogou, Safari, Firefox, Opera; and modern mobile browser.


Introducing initialization SDK JS


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


It is recommended that polyfill is introduced as well before the SDK JS, in order to work well on IE9+, e.g.


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


Configurations


new YpRiddler(options)


The options object is the configuration object. The following are the configuration parameters:

Parameter

Types

It is required?

Remarks

onSuccess

function (validInfo/token: object, close: function)

Y

Verify successful processor.Token: verify token.Close: close SDK UI.

appId

string

Y

CAPTCHA Id

version

string

Y

Interface version number

container

HTMLElement

Y

Elements for the verification logic.

noButton

boolean

F

If the mode is not the Flat, you can render the button or not.

mode

string

F

The UI access mode.flat: direct embedding mode, float: floating mode, dialog: acquiesce in dialog, external: emerge the picture on dragging the slider(only available for slide-puzzle-captcha)

onError

function

F

Verify the exception handler. If the YunPian's CAPTCHA is abnormal, it will be processed on this callback.

onFail

function (code:int, msg:string, retry:function

F

User authentication failed processor.Code: error codeMsg: error messageRetry: retry logicThe default implementation is to re-verify once.

beforeStart

function (next:string)

F

Enter the hook before the verification logic. Next: Continue to execute the subsequent logic.

expired

int

F

Request timeout, in seconds.Default is 30 seconds.

jsonpField

string

F

Jsonp processor name, and default is ypjsonp.

rsaPublicKey

string

F

Encrypt the public key.Normally you do not need to set it.

hosts

string

F

Verify server address.Normally you do not need to set it.

winWidth

number

F

Window widthThe minimum is 230px. There are 2 ways to change Window width:1. Pure number format, unit px. Default 500.2. Percent format, such as 80%, indicates the percentage of the current browser's viewable area width.

lang

string

F

Support languageZh-cn (Simplified Chinese), en (English) can be supported.

langPack

object

F

You can import the required language copy. The object needs to be set in the specified format. If the language pack is imported externally, the lang setting will be invalidated automatically.


Window width configuration


// Set the window width to a fixed value(px)
new YpRiddler({
 ...
 winWidth: '500'
 ...
})
// Set the window width to the percentage of the screen width (window width winWidth = screen width * %)
new YpRiddler({
 ...
 winWidth: '30%'
 ...
})


Lang configuration (optional)


The system supports ZH_CN by default. Currently supported languages are: zh(Chinese), and en(English).


If you need to set the language of the copy, you can set the copy content in the specified format through the external file, and then pass the language object (object) through the langPack in the options configuration item.


// Language template
const LANG_OTHER = {
 'YPcaptcha_01': 'Please click the button to start verification',
 'YPcaptcha_02': 'Please click in order:',
 'YPcaptcha_03': 'Drag the slider to the right to fill the puzzle',
 'YPcaptcha_04': 'Verification failed, please try again',
 'YPcaptcha_05': 'Successful verification'
}
new YpRiddler({
 ...
 langPack: LANG_OTHER
 ...
})


Demo


<html>

<head>
    <script src="https://www.yunpian.com/static/official/js/libs/riddler-sdk-0.2.2.js?t=20210804"></script>
    <script>
        window.onload = function () {
            //  Init...
            new YpRiddler({
                expired: 10,
                mode: 'dialog',
                winWidth: 500,
                lang: 'en',
                // langPack: LANG_OTHER, // By which you can customize languages as you like, it has higher priority than 'lang' 
                container: document.getElementById('cbox'),
                appId: 'your-app-id',
                version: 'v1',
                onError: function (param) {
                    if (param.code == 429) {
                        alert('too many requests..')
                        return
                    }
                    console.error('exception..')
                },
                onSuccess: function (validInfo, close, useDefaultSuccess) {
                    // success callback
                    alert('Verified successfully! token=' + validInfo.token + ', authenticate=' + validInfo.authenticate)
                    // default success style
                    useDefaultSuccess(true)
                    close()
                },
                onFail: function (code, msg, retry) {
                    // fail callback
                    alert('error:' + msg + ' code: ' + code)
                    retry()
                },
                beforeStart: function (next) {
                    console.log('before start...')
                    next()
                },
                onExit: function () {
                    // only dialog mode valid
                    console.log('exit verification')
                }
            })
        }
    </script>
</head>

<body>
    <div id="cbox"></div>
</body>

</html>


Successful access sample


The request record will be viewed through the Google browser's Network, if the front-end access is completed. The verify request returns two parameters: authenticate and token.



Backend access


Interface name


Secondary verification interface


Interface address


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


Request description


Request method: POST


Request type: application/x-www-form-urlencoded


Request parameter

Parameter

Types

It is required?

Remarks

captchaId

string

Y

App id

token

string

Y

The token will be provided from the front-end submit.The token will be as a sign of once verification.

authenticate

string

Y

When authentication is successful, the parameter will be provided from the front-end submit.

secretId

string

Y

The request key id.

version

string

Y

The fixed value is 1.0.

user

string

F

optional valueIf you are concerned about information disclosure, can be given in summary mode

timestamp

string

Y

The current timestamp is millisecond value , such as 1541064141441.

nonce

string

Y

Random positive integer(1-99999)Nonce & timestamp can prevent message replay.

signature

string

Y

signature information


Supported languages and Demo


Java


import java.io.IOException;
import java.net.URISyntaxException;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import java.util.Random;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.methods.PostMethod;

/**
 * A demo for YunPian CAPTCHA authenticate API
 */
public class AuthenticateDemo {

  private static String AUTH_URL = "https://captcha.yunpian.com/v1/api/authenticate";

  public static void main(String[] args) throws IOException, URISyntaxException {
    Map<String, String> paramMap = new HashMap<>();
    // replace the following "{example}"s with actual values
    paramMap.put("captchaId", "{captchaId}");
    paramMap.put("secretId", "{secretId}");
    paramMap.put("token", "{token}");
    paramMap.put("authenticate", "{authenticate}");
    paramMap.put("version", "1.0");
    paramMap.put("timestamp", String.valueOf(System.currentTimeMillis()));
    paramMap.put("nonce", String.valueOf(new Random().nextInt(99999)));
    paramMap.put("user", "{user}"); // user is optional

    String signature = genSignature("{secretKey}", paramMap);
    paramMap.put("signature", signature);

    StringBuilder sb = new StringBuilder();
    PostMethod postMethod = new PostMethod(AUTH_URL);
    postMethod.addRequestHeader("Content-Type", "application/x-www-form-urlencoded");
    paramMap.forEach((k, v) -> {
      postMethod.addParameter(k, v);
    });
    HttpClient httpClient = new HttpClient();
    int status = httpClient.executeMethod(postMethod);
    String responseBodyAsString = postMethod.getResponseBodyAsString();
    System.out.println(responseBodyAsString);
  }

  // generate signature
  private static String genSignature(String secretKey, Map<String, String> params) {
    String[] keys = params.keySet().toArray(new String[0]);
    Arrays.sort(keys);
    StringBuilder sb = new StringBuilder();
    for (String key : keys) {
      sb.append(key).append(params.get(key));
    }
    sb.append(secretKey);
    return DigestUtils.md5Hex(sb.toString());
  }
}


C


using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Security.Cryptography;
using System.Text;
using System.Web;

namespace ConsoleApp1
{
    /// A demo for YunPian CAPTCHA authenticate API
    class AuthenticateDemo
    {
        protected const string AUTH_URL = "https://captcha.yunpian.com/v1/api/authenticate";
        protected const string VERSION = "1.0";
        protected const int MAX_NONCE = 99999;

        static void Main(string[] args)
        {
            Dictionary<string, string> parameters = new Dictionary<string, string>();
            // replace the following "{example}"s with actual values!!!
            parameters.Add("captchaId", "{captchaId}");
            parameters.Add("secretId", "{secretId}");
            parameters.Add("token", "{token}");
            parameters.Add("authenticate", "{authenticate}");
            parameters.Add("version", VERSION);
            parameters.Add("timestamp", GetCurrentTimeMillis());
            parameters.Add("nonce", GetNonce().ToString());
            //parameters.Add("user", "{user}"); // user is optional

            // generate signature
            string sign = GenSignature("{secretKey}", parameters);
            parameters.Add("signature", sign);

            // authenticate
            string retString = PostAuthData(parameters);
            Console.WriteLine(retString);
        }

        // post authenticate data
        public static string PostAuthData(Dictionary<string, string> parameters)
        {
            StringBuilder sb = new StringBuilder();
            foreach (var item in parameters)
            {
                if (sb.Length > 0)
                    sb.Append("&");
                sb.Append(item.Key + "=" + HttpUtility.UrlEncode(item.Value, System.Text.Encoding.UTF8));
            }
            string data = sb.ToString();

            HttpWebRequest request = (HttpWebRequest)WebRequest.Create(AUTH_URL);
            request.Timeout = 30 * 1000;

            request.Method = "POST";
            request.ContentType = "application/x-www-form-urlencoded";
            request.ContentLength = Encoding.UTF8.GetByteCount(data);

            Stream myRequestStream = request.GetRequestStream();
            byte[] requestBytes = System.Text.Encoding.ASCII.GetBytes(data);
            myRequestStream.Write(requestBytes, 0, requestBytes.Length);
            myRequestStream.Close();

            HttpWebResponse response = (HttpWebResponse)request.GetResponse();
            Stream myResponseStream = response.GetResponseStream();
            StreamReader myStreamReader = new StreamReader(myResponseStream, Encoding.GetEncoding("utf-8"));
            string retString = myStreamReader.ReadToEnd();
            myStreamReader.Close();
            myResponseStream.Close();

            return retString;
        }
        // generate signature
        public static String GenSignature(String secretKey, Dictionary<String, String> parameters)
        {
            parameters = parameters.OrderBy(o => o.Key).ToDictionary(o => o.Key, p => p.Value);
            StringBuilder builder = new StringBuilder();
            foreach (KeyValuePair<String, String> kv in parameters)
            {
                builder.Append(kv.Key).Append(kv.Value);
            }
            builder.Append(secretKey);
            String tmp = builder.ToString();
            MD5 md5 = new MD5CryptoServiceProvider();
            byte[] result = md5.ComputeHash(Encoding.UTF8.GetBytes(tmp));
            builder.Clear();
            foreach (byte b in result)
            {
                builder.Append(b.ToString("x2"));
            }
            return builder.ToString();
        }

        private static int GetNonce()
        {
            Random r = new Random();
            int n = r.Next(1, MAX_NONCE);
            return n;
        }

        private static String GetCurrentTimeMillis()
        {
            TimeSpan ts = DateTime.UtcNow - new DateTime(1970, 1, 1, 0, 0, 0, 0);
            return Convert.ToInt64(ts.TotalMilliseconds).ToString();
        }
    }
}


PHP


<?php
$params = array();
$params["authenticate"] ="{authenticate}"; // authenticate code
$params["token"] ="{token}"; // token
$params["captchaId"] ="{captchaId}"; // captchaId
$params["secretId"] ="{secretId}"; // secretId
$secretKey = "{secretKey}"; // secretKey
$params["version"] = "1.0";
$params["timestamp"] = sprintf("%d", round(microtime(true)*1000));
$params["nonce"] = sprintf("%d", rand(1,99999));
ksort($params);
$buff="";

foreach($params as $key=>$value){
        $buff .=$key;
        $buff .=$value;
}
$buff .= $secretKey;
//print_r($buff);
$signature=md5($buff);
$params["signature"] =$signature ;

$url="https://captcha.yunpian.com/v1/api/authenticate";
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_TIMEOUT, 10);
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($ch, CURLOPT_HTTPHEADER, array('Content-Type:application/x-www-form-urlencoded'));
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($params));
$result = curl_exec($ch);
var_dump($result);


Python


import random
import time
import hashlib
import requests

authenticate = '{authenticate}'
secretKey = '{secretKey}'
token = '{token}'
captchaId = '{captchaId}'
secretId = '{secretId}'

data = {
  'authenticate': authenticate,
  'captchaId': captchaId,
  'nonce': str(random.randint(10000, 99999)),
  'secretId': secretId,
  'timestamp': str(time.time()).split('.')[0],
  'token': token,
  'version': '1.0'
}
print '%s: %s' % ('data', data)


sign_str = ''
items = sorted(data.items(), key=lambda d:d[0])

for item in items:
  sign_str += '%s%s' % (item[0],item[1])

sign_str += secretKey
print '%s: %s' % ('sign_str', sign_str)

signature = hashlib.md5(sign_str).hexdigest().lower()
data['signature'] = signature

print '%s: %s' % ('data', data)

url = 'https://captcha.yunpian.com/v1/api/authenticate'
headers = {'Content-Type': 'application/x-www-form-urlencoded'}

r = requests.post(url, data=data, headers=headers)

print r.text


Additional instructions:


1、Signature calculation method


Step 1:


Sort all request parameters (excluding the signature parameter) in ascending order of the parameter name ASCII table. Such as: foo=1, bar=2, foo_bar=3, baz=4 The order after sorting is bar=2, baz=4, foo=1, foo_bar=3.


Step 2:


Construct the sorted parameter name and parameter value into a string in the format: key1+value1+key2+value2... The result of the construction obtained from the above example is: bar2baz4foo1foo_bar3.


Step 3:


Select the secretKey paired with the secretId and add it to the parameter string constructed in the previous step, such as secretKey=e3da918313c14ea8b25db31f01263f80, then the last parameter string is bar2barz4foo1foo_bar3e3da918313c14ea8b25db31f01263f80.


Step 4:


the 3-step assembled string is encoded by utf-8, and the MD5 algorithm is used to summarize the string, and the signature parameter value is calculated and added to the interface request parameter. MD5 is a 128-bit length digest algorithm, expressed in hexadecimal. A hexadecimal character can represent 4 bits, so the length of the signed string is fixed to 32 hexadecimal characters. The result of the above signature is: 59db908f26fb997c30b32ddb911485c2.


/**
 * 生成签名信息
 * @param secretKey 应用私钥
 * @param params 接口请求参数名和参数值map,不包括signature参数名
 * @return
 */
public static String genSignature(String secretKey, Map<String, String> params){
    // 1. 参数名按照ASCII码表升序排序
    String[] keys = params.keySet().toArray(new String[0]);
    Arrays.sort(keys);

    // 2. 按照排序拼接参数名与参数值
    StringBuilder sb = new StringBuilder();
    for (String key : keys) {
        sb.append(key).append(params.get(key));
    }
    // 3. 将secretKey拼接到最后
    sb.append(secretKey);

    // 4. MD5是128位长度的摘要算法,转换为十六进制之后长度为32字符
    return DigestUtils.md5Hex(sb.toString().getBytes("UTF-8"));
}


2、 Response code interpretation


Front end


Verify interface

Response code

Error message

specific description

0

ok

verification passed

1

bad request

verify request data is missing or malformed

2

verify fail

verification failed

400

param_invalid

request parameter error, check i k parameter

429

too many requests

requests are too frequent, please try again later

500

server_error

service exception


Get interface

response code

error message

specific description

0

ok

get the verification image successfully

400

param_invalid

request parameter error, check i k parameter

400

captcha_id_invalid

captchaId does not exist

403

forbidden request

The unusual requests are forbidden

429

too many requests

Requests are too frequent, please try again later

500

server_error

service exception


Backend


Response Parameter

Parameter

Types

It is required?

Remarks

code

int

Y

0: the success verificationnon-zero: the abnormal information For details, see “Secondary verification interface response code interpretation” below.

msg

string

Y

error description


Secondary verification interface response code interpretation

response code

error message

specific description

0

ok

Secondary verification successfully

400

validate_fail

secondary verification does not pass

400

signature_invalid

signature verification failed

400

param_invalid

request parameter error, check i k parameter

400

captcha_id_invalid

captchaId does not exist

429

too many requests

Requests are too frequent, please try again later

500

server_error

service exception