package sms import ( "crypto/hmac" "crypto/sha256" "encoding/hex" "encoding/json" "errors" "fmt" "io/ioutil" "net/http" "net/url" "time" ) // 验证服务地址 const API_SERVER string = "https://captcha.alicaptcha.com" // 二次校验接口 const URL = API_SERVER + "/validate" + "?captcha_id=" // 图形校验 func AliyunCheckCaptcha(CaptchaId, CaptchaKey string, datas map[string]string) error { lotNumber := datas["lot_number"] captchaOutput := datas["captcha_output"] passToken := datas["pass_token"] genTime := datas["gen_time"] // 生成签名 // 生成签名使用标准的hmac算法,使用用户当前完成验证的流水号lot_number作为原始消息message,使用客户验证私钥作为key // 采用sha256散列算法将message和key进行单向散列生成最终的 “sign_token” 签名 signToken := hmac_encode(CaptchaKey, lotNumber) // 向验证服务转发前端数据 + “sign_token” 签名 formData := make(url.Values) formData["lot_number"] = []string{lotNumber} formData["captcha_output"] = []string{captchaOutput} formData["pass_token"] = []string{passToken} formData["gen_time"] = []string{genTime} formData["sign_token"] = []string{signToken} // 发起post请求 // 设置5s超时 cli := http.Client{Timeout: time.Second * 5} resp, err := cli.PostForm(URL+CaptchaId, formData) if err != nil || resp.StatusCode != 200 { // 当请求发生异常时,应放行通过,以免阻塞业务 fmt.Println("服务接口异常: ") fmt.Println(err) return errors.New("验证失败") } resJson, _ := ioutil.ReadAll(resp.Body) var resMap map[string]interface{} // 根据验证服务返回的用户验证状态, 网站主进行自己的业务逻辑 // 响应json数据如:{"result": "success", "reason": "", "captcha_args": {}} if err = json.Unmarshal(resJson, &resMap); err != nil { fmt.Println("Json数据解析错误") return errors.New("验证失败") } result := resMap["result"] if result == "success" { fmt.Println("验证通过") return nil } else { reason := resMap["reason"] fmt.Print("验证失败: ") fmt.Print(reason) return errors.New("验证失败") } } // hmac-sha256 加密: CAPTCHA_KEY,lot_number func hmac_encode(key string, data string) string { mac := hmac.New(sha256.New, []byte(key)) mac.Write([]byte(data)) return hex.EncodeToString(mac.Sum(nil)) }