用法PHP示例主要代码
session_start();
$verifier = new NECaptchaVerifier(YIDUN_CAPTCHA_ID, new SecretPair(YIDUN_CAPTCHA_SECRET_ID, YIDUN_CAPTCHA_SECRET_KEY));
$validate = $_POST['NECaptchaValidate']; // 获得验证码二次校验数据
if(get_magic_quotes_gpc()){// PHP 5.4之前默认会将参数值里的 \ 转义成 \\,这里做一下反转义
$validate = stripcslashes($validate);
}
$user = "{'user':123456}"; // 当前用户信息,值可为空
/** @var $result bool */
$result = $verifier->verify($validate, $user);
SDK接入文档: http://support.dun.163.com/documents/15588062143475712?docId=69218161355051008
github示例地址
git remote -v
origin https://github.com/yidun/captcha-php-demo (fetch)
origin https://github.com/yidun/captcha-php-demo (push)
改为golang版本
* SecretPair.go
package captcha
type SecretPair struct {
SecretId string
SecretKey string
}
func NewSecretPair(secretId string, secretKey string) *SecretPair {
return &SecretPair{
SecretId: secretId,
SecretKey: secretKey,
}
}
https://stackoverflow.com/questions/16895294/how-to-set-timeout-for-http-get-requests-in-golang
golang http client
timeout := time.Duration(5 * time.Second)
client := http.Client{
Timeout: timeout,
}
client.Get(url)
* NECaptchaVerifier.go
package captcha
import (
"bytes"
"crypto/md5"
"encoding/json"
"errors"
"fmt"
"github.com/Unknwon/com"
"io/ioutil"
"math/rand"
"net/http"
"sort"
"strings"
"time"
)
// @ref: https://github.com/yidun/captcha-php-demo
// @ref: http://support.dun.163.com/documents/15588062143475712?docId=69218161355051008
const (
YIDUN_CAPTCHA_API_VERSION = "v2"
YIDUN_CAPTCHA_API_TIMEOUT = 5
YIDUN_CAPTCHA_API_URL = "http://c.dun.163yun.com/api/v2/verify"
)
type NECaptchaVerifier struct {
CaptchaID string
SecretPair SecretPair
}
type NEResponse struct {
Msg string `json:"msg"`
Result bool `json:"result"`
Error int `json:"error"`
}
// 发起二次校验请求
// @param validate string 二次校验数据
// @param user 用户信息
func (this *NECaptchaVerifier) Verify(validate string, user string) (*NEResponse, error) {
params := map[string]string{}
params["captchaId"] = this.CaptchaID
params["validate"] = validate
params["user"] = user
params["secretId"] = this.SecretPair.SecretId
params["version"] = YIDUN_CAPTCHA_API_VERSION
// time in millisecond
params["timestamp"] = fmt.Sprintf("%d", time.Now().Unix()*1000)
// random int
rand.Seed(time.Now().UnixNano())
params["nonce"] = fmt.Sprintf("%d", rand.Uint32())
params["signature"] = genSignature(this.SecretPair.SecretKey, params)
var result string
var err error
var ne NEResponse
result, err = this.sendHttpResquest(params)
if err != nil {
return nil, errors.New(fmt.Sprintf("send http request error: %s", err.Error()))
}
fmt.Println(result)
// json deocode
err = json.Unmarshal([]byte(result), &ne)
if err != nil {
return nil, errors.New(fmt.Sprintf("json decode error: %s", err.Error()))
}
return &ne, err
}
// 计算参数签名
// @param secretKey 密钥对key
// @param params 请求参数
func genSignature(secretKey string, params map[string]string) string {
var keys []string
for key, _ := range params {
keys = append(keys, key)
}
sort.Strings(keys)
buf := bytes.NewBufferString("")
for _, key := range keys {
buf.WriteString(key + params[key])
}
buf.WriteString(secretKey)
fmt.Printf("signature=%s\n", buf.String())
has := md5.Sum(buf.Bytes())
return fmt.Sprintf("%x", has)
}
/**
* 发送http请求
* @param $params 请求参数
*/
func (*NECaptchaVerifier) sendHttpResquest(params map[string]string) (string, error) {
client := &http.Client{
Timeout: time.Second * YIDUN_CAPTCHA_API_TIMEOUT,
}
url := YIDUN_CAPTCHA_API_URL
postString := http_build_query(params)
req, err := http.NewRequest(http.MethodPost, url, strings.NewReader(postString))
if err != nil {
return "", err
}
fmt.Printf("POST %s\n", url)
fmt.Printf("[%s]\n", postString)
for key, value := range params {
fmt.Printf("%s = %s\n", key, value)
}
req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
req.Header.Set("Accept", "application/json")
req.Header.Set("Content-Length", fmt.Sprintf("%d", len(postString)))
req.Header.Set("Upgrade-Insecure-Requests", "1")
resp, err := client.Do(req)
defer resp.Body.Close()
if err != nil {
return "", err
}
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
return "", err
}
return string(body), nil
}
func http_build_query(params map[string]string) string {
var a []string
for k, v := range params {
a = append(a, fmt.Sprintf("%s=%s", k, com.UrlEncode(v)))
}
return strings.Join(a, "&")
}
* SecretPair.go
package captcha
type SecretPair struct {
SecretId string
SecretKey string
}
func NewSecretPair(secretId string, secretKey string) *SecretPair {
return &SecretPair{
SecretId: secretId,
SecretKey: secretKey,
}
}
* Captcha.go
package captcha
import (
"fmt"
"github.com/kataras/iris/core/errors"
"github.com/spf13/viper"
)
type Captcha struct {
Validate string // $_POST["NECaptchaValidate"]
Data string // "{'user':123456}"
}
func (this *Captcha) Verify() (bool, error) {
var verifier = NECaptchaVerifier{
CaptchaID: viper.GetString("YIDUN_CAPTCHA_ID"),
SecretPair: *NewSecretPair(
viper.GetString("YIDUN_CAPTCHA_SECRET_ID"),
viper.GetString("YIDUN_CAPTCHA_SECRET_KEY")),
}
fmt.Println(verifier)
if len(this.Validate) < 1 {
return false, errors.New("NECaptchaValidate can't be empty")
}
result, err := verifier.Verify(this.Validate, this.Data)
fmt.Println(result)
if err != nil {
fmt.Println(err)
return false, err
}
// {"msg":"PARAM_ERROR","result":false,"error":419}
if !result.Result {
return result.Result, errors.New(
fmt.Sprintf("error:%d, msg:%s", result.Error, result.Msg))
}
// {"msg":OK, "result":true, "error"0}
return result.Result, nil
}
* index.html
易盾验证码-DEMO
php -S 0.0.0.0:8082
浏览器访问 http://127.0.0.1:8082