# 点选文字验证码

我们准备了ba\ClickCaptcha类,和clickCaptcha组件,实现了前端的点选文字验证码和服务端的二次验证。

# 使用思路

clickCaptcha(id: string, callback?: (captchaInfo: string) => void, options: ClickCaptchaOptions = {})
  1. 用户提交表单等操作前,传递验证码ID调起文字点选验证码,用户完成验证后将生成点选文字坐标信息(captchaInfo)
  2. 在验证完成回调中,将验证码ID点选文字坐标信息随表单数据发送到服务端,并在接口中使用对应方法对坐标信息进行二次验证
  3. 开发者往往无需关注坐标信息,以及封装好的验证逻辑等,只需看懂下方示例即可方便快捷的使用文字点选验证码
  • 前端
import { reactive } from 'vue'
import { uuid } from '/@/utils/random'
import clickCaptcha from '/@/components/clickCaptcha'

// 表单数据
const form = reactive({
    // 验证码ID,开发者自定义,随表单数据发送到服务端供二次验证
    captchaId: uuid(),
    // 用户点选的文字坐标信息,随表单数据发送到服务端供二次验证
    captchaInfo: '',
    // 假设的表单字段
    username: '',
    password: '',
})

const onSubmitPre = () => {
    // 假设表单设置了验证规则
    formRef.value?.validate((valid) => {
        if (!valid) return

        /**
         * 调用此函数,自动调起点选文字验证码弹窗
         * 参数一:验证码ID
         * 参数二:验证成功后的回调函数
         * 参数三:额外的可配置项
         */
        clickCaptcha(form.captchaId, (captchaInfo: string) => onSubmit(captchaInfo))
    })
}

const onSubmit = (captchaInfo = '') => {
    // 在回调函数中一定要更新 form 中的验证数据,否则服务端验证将失败
    form.captchaInfo = captchaInfo

    login('post', form).then((res) => {
        // 请求成功
    })
}
  • 服务端
$captchaId   = $this->request->post('captchaId');
$captchaInfo = $this->request->post('captchaInfo');

$captcha = new \ba\ClickCaptcha();
if (!$captcha->check($captchaId, $captchaInfo)) {
    $this->error('验证码错误!');
}

// 您的业务逻辑...

# 点选验证码的实现思路

如果您需要在比如uniapp等其他平台实现点选验证码,实现思路如下,它非常简单!

  1. 携带一个自定义的id字符串请求验证码接口
  2. 该接口返回一张base64编码的图片图片的宽高(通常为350*200)、四个随机中文汉字
  3. 您只需要渲染返回的图片,并要求用户按四个随机中文汉字的顺序点击四下
  4. 将用户四次点击事件的坐标按简单规则拼接,同id发送至服务器即可完成验证
  5. 以上仅为思路,实现请直接参考/web/src/components/clickCaptcha/index.vue

# 普通验证码

我们准备了ba\Captcha类,该类基于TP的验证码类改造而成:通过Mysql保存验证码而不是Session以更好的支持API访问。

使用验证码类的方法如下:

  1. 前端生成一个唯一的id
  2. 携带id请求验证码生成接口,该接口应直接输出图片,比如:/index.php/api/common/captcha
  3. 提交表单时,携带id,以对验证码的正确性进行验证。

# 验证码生成示例

// 接受ID
$captchaId = $this->request->request('id');

// 一些验证码的基本配置
$config    = array(
    'codeSet'  => '123456789',            // 验证码字符集合
    'fontSize' => 22,                     // 验证码字体大小(px)
    'useCurve' => false,                  // 是否画混淆曲线
    'useNoise' => true,                   // 是否添加杂点
    'length'   => 4,                      // 验证码位数
    'bg'       => array(255, 255, 255),   // 背景颜色
);

// 实例化验证码类,传递`ID`并输出验证码
$captcha = new Captcha($config);
return $captcha->entry($captchaId);

# 验证码验证示例

// 接受验证码和验证码ID
$data['captcha']   = $this->request->post('captcha');
$data['captchaId'] = $this->request->post('captcha_id');

$captchaObj = new Captcha();
if (!$captchaObj->check($data['captcha'], $data['captchaId'])) {
    $this->error('验证码错误!');
}

# 普通验证码高级应用

验证码类,不仅仅可以生成图像验证码,几乎支持所有:给用户展示/发送一个字符串,要求用户输入看到的字符进行身份验证的场景

# 发送邮箱验证码

// 准备一个 id ,此处使用一个前缀+发信邮箱地址,但总的来说它是完全自定义的
$id = 'user_email_verify:' . $this->auth->email;

$captcha = new Captcha();
$code    = $captcha->create($id);

// 将 $code 发送到用户邮箱,它是自动生成的字符串,您也可以通过参数二指定一个字符串
// ...
// $mail->send();

# 验证邮箱验证码

$id = 'user_email_verify:' . $this->auth->email;
$code = $this->request->post('code');
$captcha = new Captcha();
$captcha->check($code, $id);

给验证码设定一个id,通过这个id生成的验证码自然可以通过该id完成验证,而id是完全自定义的。

# 普通验证码配置

验证码类带有默认的配置参数,也支持自定义配置,这些配置项包括:

配置项 注释 默认值
codeSet 验证码字符串集合 数字、大小写字母,(以去除1l0o等容易混淆的字符)
expire 验证码过期时间(秒) 600秒(10分钟)
useZh 使用中文验证码 false
zhSet 中文验证码字符串 一些预设的汉字
useImgBg 使用图片背景 false
fontSize 验证码字体大小(px) 25(px)
useCurve 是否画混淆曲线 true
useNoise 是否添加杂点 true
imageH 验证码图片高度 0:自动计算
imageW 验证码图片宽度 0:自动计算
length 验证码位数 验证码位数
fontttf 验证码字体,不设置则随机获取
bg 验证码背景色 rgb[243, 251, 254]
reset 验证成功后重置 true