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 |