工作笔记 - 腾讯云验证码(滑动验证)接入

1,151 阅读4分钟

客户端

Web

引用 TCaptcha SDK

<script src="https://turing.captcha.qcloud.com/TCaptcha.js"></script>

TCaptcha SDK 会在全局注册一个 TencentCaptcha 类,可以使用这个类自行初始化验证码,并对验证码进行显示或者隐藏。

/**
  * 创建 TencentCaptcha 实例
  * Your CaptchaId: 在腾讯云验证码控制台创建的应用的 ID
  * Callback: ({
  *    ret,          // Number 验证结果,0:验证成功。2:用户主动关闭验证码。
  *    ticket,       // String 验证成功的票据,当且仅当 ret = 0 时 ticket 有值。
  *    appid,        // String 验证码应用 ID。
  *    bizState,     // Any 自定义透传参数。
  *    randstr,      // String 本次验证的随机串,后续票据校验时需传递该参数。
  *    errorCode,    // Number 错误 code ,详情请参见 @docs https://cloud.tencent.com/document/product/1110/36841#errorCode
  *    errorMessage, // String 错误信息。
  * }) => void
  */
const captcha = new TencentCaptcha("Your CaptchaId", async result => {
    if (result.ret === 0) {
        const { ticket, randstr } = result
        const data = { ticket, randstr, "Other business data" }
        /**
         * 向服务端业务接口发起请求,并携带 ticket, randstr
         * 服务端向腾讯云确认本次验证有效性
         */
        fetch("Your Server Url", { 
            method: "POST", 
            headers: { "Content-Type": "application/json" }, 
            body: JSON.stringify(data),  
        }) 
    }
    // else 
})
// 唤起验证窗口
captcha.show()

Weapp

Step 1. 登录 微信公众平台,设置 > 第三方设置 > 添加插件中,添加“腾讯验证码”

4bad98dc4ae506538073b95fb7fb66ca.png

Step 2. 配置小程序插件 app.json

{
     "plugins": {
         "captcha": {
             "version": "1.0.4", //请选择小程序插件最新版本
             "provider": "wx1fe8d9a3cb067a75"
         }
     }
}

Step 3. 使用小程序插件

xxx.json or app.json

{
     "usingComponents": {
       "t-captcha": "plugin://captcha/t-captcha"
     }
}

xxx.wxml

<t-captcha
    id="captcha"
    app-id="Your CaptchaId"
    <!-- 验证码准备就绪 -->
    bindverify="handlerVerifyAndLogin"
    <!-- 验证码验证完成 -->
    bindready="handlerReady"
    <!-- 验证码弹框准备关闭 -->
    bindclose="handlerClose"
    <!-- 验证码配置失败 -->
    binderror="handlerError" />
<button bindtap='handleShowCaptcha'>登录</button>

xxx.js

Page({
    data: {},
    // 唤起验证码
    handleShowCaptcha: function () {
        this.selectComponent("#captcha").show()
    }

    // 验证码验证结果回调
    handlerVerifyAndLogin: function (ev) {
        // 这里的处理逻辑与 web 端一致
        // 不同点是小程序插件不回返回 randstr 参数,只需传递 ticket 给后端即可
    },

    // 验证码准备就绪
    handlerReady: function () { },

    // 验证码弹框准备关闭
    handlerClose: function (ev) { },

    // 验证码出错
    handlerError: function (ev) { }

})

Typescript

如果你的项目中应用了 typescript,可将下方类型声明添加到你的 xx.d.ts 中,简单写了写可自行完善

namespace TencentCaptcha {
    /**
     * 验证码应用 ID。
     */
    export type CaptchaAppId = string
    /**
     * 验证码应用回调参数
     */
    export type CallBackResult = {
        /**
         * 验证结果,0:验证成功。2:用户主动关闭验证码。
         */
        ret: 0 | 2
        /**
         * 验证成功的票据,当且仅当 ret = 0 时 ticket 有值。
         */
        ticket: string
        /**
         * 验证码应用 ID。
         */
        appid: string
        /**
         *  自定义透传参数。
         */
        bizState: any
        /**
         * 本次验证的随机串,后续票据校验时需传递该参数。
         */
        randstr: string
        /**
         * 错误 code ,详情请参见
         * @docs https://cloud.tencent.com/document/product/1110/36841#errorCode
         */
        errorCode: number
        /**
         * 错误信息
         */
        errorMessage: string
    }
    /**
     * 验证码应用回调函数
     */
    export type CallBack = (res: CallBackResult) => void

    /**
     * 验证码应用外观
     * TODO: 待完善
     */
    export type Options = any
}

declare class TencentCaptcha {
    constructor(
        appid: TencentCaptcha.CaptchaAppId,
        callback: TencentCaptcha.CallBack,
        options?: TencentCaptcha.Options
    )
    show()
}

服务端(Java)

pom.xml

<dependency>
    <groupId>com.tencentcloudapi</groupId>
    <artifactId>tencentcloud-sdk-java</artifactId>
    <!-- go to https://search.maven.org/search?q=tencentcloud-sdk-java and get the latest version. -->
    <!-- 请到https://search.maven.org/search?q=tencentcloud-sdk-java查询所有版本,最新版本如下 -->
    <version>3.1.984</version>
</dependency>

application.properties

secretId & secretkey 可前往官网控制台 console.cloud.tencent.com/cam/capi 进行获取

captchaAppId & appSecretKey 登录 验证码控制台,在验证列表的【密钥】列,即可查看到

captcha.captchaType 滑动验证固定值为 9,可在控制台配置不同验证码类型

captcha.secretId=Your Secret Id
captcha.secretKey=Your Secret Key
captcha.captchaAppId=Your Captcha AppId
captcha.appSecretKey=Your App Secret Key
captcha.captchaType=9

CaptchaConfig.java

package com.xxx.tencentcaptchademo.config;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import java.util.Objects;

@Component
public class CaptchaConfig {

    @Value("${captcha.secretId}")
    private String secretId;
    @Value("${captcha.secretKey}")
    private String secretKey;
    @Value("${captcha.captchaAppId}")
    private Long captchaAppId;
    @Value("${captcha.appSecretKey}")
    private String appSecretKey;
    @Value("${captcha.captchaType}")
    private Long captchaType;


    public String getSecretId() {
        return secretId;
    }

    public void setSecretId(String secretId) {
        this.secretId = secretId;
    }

    public String getSecretKey() {
        return secretKey;
    }

    public void setSecretKey(String secretKey) {
        this.secretKey = secretKey;
    }

    public Long getCaptchaAppId() {
        return captchaAppId;
    }

    public void setCaptchaAppId(Long captchaAppId) {
        this.captchaAppId = captchaAppId;
    }

    public String getAppSecretKey() {
        return appSecretKey;
    }

    public void setAppSecretKey(String appSecretKey) {
        this.appSecretKey = appSecretKey;
    }

    public Long getCaptchaType() {
        return captchaType;
    }

    public void setCaptchaType(Long captchaType) {
        this.captchaType = captchaType;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        CaptchaConfig that = (CaptchaConfig) o;
        return Objects.equals(secretId, that.secretId) && Objects.equals(secretKey, that.secretKey) && Objects.equals(captchaAppId, that.captchaAppId) && Objects.equals(appSecretKey, that.appSecretKey) && Objects.equals(captchaType, that.captchaType);
    }

    @Override
    public int hashCode() {
        return Objects.hash(secretId, secretKey, captchaAppId, appSecretKey, captchaType);
    }

    @Override
    public String toString() {
        return "CaptchaConfig{" +
                "secretId='" + secretId + ''' +
                ", secretKey='" + secretKey + ''' +
                ", captchaAppId=" + captchaAppId +
                ", appSecretKey='" + appSecretKey + ''' +
                ", captchaType=" + captchaType +
                '}';
    }
}

CaptchaController.java

package com.xxx.tencentcaptchademo.controller;

import com.tencentcloudapi.common.exception.TencentCloudSDKException;
import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletRequest;
import net.wangsl.tencentcaptchademo.service.CaptchaService;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;

@Controller
@RequestMapping("/captcha")
public class CaptchaController {

    @Resource
    private CaptchaService cts;

    @RequestMapping("/verification/web")
    @ResponseBody
    public String authWebTicket(@RequestParam("ticket") String ticket, @RequestParam("randstr") String randstr, HttpServletRequest request) throws TencentCloudSDKException {
        return cts.authWebTicket(ticket, randstr, request.getRemoteAddr());
    }

    @RequestMapping("/verification/weapp")
    @ResponseBody
    public String authWeappTicket(@RequestParam("ticket") String ticket, HttpServletRequest request) throws TencentCloudSDKException {
        return cts.authWeappTicket(ticket, request.getRemoteAddr());
    }
}

CaptchaService.java

注意 weappweb 最大的不同就是 weapprandstr 字段

package com.xxx.tencentcaptchademo.service;

import com.tencentcloudapi.captcha.v20190722.CaptchaClient;
import com.tencentcloudapi.captcha.v20190722.models.*;
import com.tencentcloudapi.common.Credential;
import com.tencentcloudapi.common.exception.TencentCloudSDKException;
import jakarta.annotation.Resource;
import net.wangsl.tencentcaptchademo.config.CaptchaConfig;
import org.springframework.stereotype.Service;

@Service
public class CaptchaService {

    @Resource
    CaptchaConfig captchaConfig;
    
    /**
     * 校验 web 端滑动验证是否有效
     */
    public String authWebTicket(String ticket, String randstr, String IP) throws TencentCloudSDKException {
        Credential cred = new Credential(captchaConfig.getSecretId(), captchaConfig.getSecretKey());
        // 创建验证码客户端实例
        CaptchaClient client = new CaptchaClient(cred, "");
        // 创建获取验证码结果的请求对象
        DescribeCaptchaResultRequest req = new DescribeCaptchaResultRequest();
        // 设置验证码应用 ID
        req.setCaptchaAppId(captchaConfig.getCaptchaAppId());
        // 设置验证码应用的密钥
        req.setAppSecretKey(captchaConfig.getAppSecretKey());
        // 设置验证码类型
        req.setCaptchaType(captchaConfig.getCaptchaType());
        // 设置本次验证的随机串
        req.setRandstr(randstr);
        // 设置用户 IP 地址
        req.setUserIp(IP);
        // 设置本次验证的票据
        req.setTicket(ticket);
        // 初始化响应对象
        DescribeCaptchaResultResponse resp = null;
        // 调用客户端的方法,获取验证码验证结果
        resp = client.DescribeCaptchaResult(req);
        // 将验证码验证结果转换为 JSON 字符串并返回
        return DescribeCaptchaTicketDataResponse.toJsonString(resp);
    }
    
    /**
     * 校验 weapp 端滑动验证是否有效
     * 跟上边函数的区别就是 DescribeCaptchaResultRequest to DescribeCaptchaMiniResultRequest
     */
    public String authWeappTicket(String ticket, String IP) throws TencentCloudSDKException {
        Credential cred = new Credential(captchaConfig.getSecretId(), captchaConfig.getSecretKey());
        CaptchaClient client = new CaptchaClient(cred, "");
        DescribeCaptchaMiniResultRequest req = new DescribeCaptchaMiniResultRequest();
        req.setCaptchaAppId(captchaConfig.getCaptchaAppId());
        req.setAppSecretKey(captchaConfig.getAppSecretKey());
        req.setCaptchaType(captchaConfig.getCaptchaType());
        req.setUserIp(IP);
        req.setTicket(ticket);
        DescribeCaptchaMiniResultResponse resp = null;
        resp = client.DescribeCaptchaMiniResult(req);
        return DescribeCaptchaMiniResultResponse.toJsonString(resp);
    }
}