行为式验证码

发布于 2026 年 10 月 23 日 星期五

Vue 验证码前后端分离怎么接?滑块回调与服务端校验示例

Vue 滑块显示成功后,后端还要做什么?用不墨验证码演示产品 ID、API KEY、captchaId 的分工,提供 Vue 3 组件、Node.js 校验函数和失败处理检查单。

Vue 验证码前后端分离怎么接?滑块回调与服务端校验示例

Vue 接滑动验证码,最容易漏掉的是前端成功回调之后的服务端校验。组件变绿只代表拿到了一个待校验凭证;业务后端确认凭证通过,才可以执行受保护的操作。

下面以 Vue 3 和不墨行为式验证码为例。前端只负责展示、收集凭证、提交请求;API KEY 始终留在后端。示例是接入骨架,业务接口需要接到你已有的服务里,不是完整注册系统。

先分清三个值

  • 产品 ID:前端初始化 SDK 用,也用于服务端请求的 x-id。从产品控制台取得。
  • API KEY:后端调用校验服务的凭据。不要放进 Vue 的源码、VITE_ 环境变量或浏览器请求。
  • captchaId:每次滑动成功回调得到的值,前端随本次业务请求提交给后端,放在校验请求体的 r 字段里。

开通产品、创建验证码 API KEY,并将实际使用的域名加入白名单。后端 referer 使用白名单中的业务站点地址,不要照抄示例域名。字段与接口以官方 API 文档为准。

第一步:加载 SDK,再挂载 Vue

对于普通 Vue + Vite 单页应用,把下面脚本放在 index.html 的 Vue 入口脚本之前,确保组件挂载时 SDK 已经可用:

<script src="https://cdn.bumo.cc/apps/captcha-sdk/captcha.js"></script>
<script type="module" src="/src/main.js"></script>

这是最直观的加载顺序,外部脚本会阻塞后面的解析。需要异步加载时,应在脚本的 load 回调后初始化,不能只加 async 然后照常读取 window.BumoCaptcha。SSR 项目则要把 SDK 加载和初始化放到浏览器端执行。

第二步:在 Vue 3 组件里传递凭证

把 YOUR_PRODUCT_ID 替换成控制台给出的产品 ID。示例假设此组件在页面上只挂载一次;同页多个组件需要使用不同容器 ID。

<script setup>
import { onMounted, ref } from 'vue';

const captchaId = ref('');
const busy = ref(false);
const message = ref('');
let captcha;

onMounted(() => {
  if (!window.BumoCaptcha) {
    message.value = '验证组件加载失败,请刷新重试';
    return;
  }
  captcha = new window.BumoCaptcha({
    containerId: 'BUMO_CAPTCHA',
    id: 'YOUR_PRODUCT_ID',
    successCallback: (id) => { captchaId.value = id; },
    failCallback: () => { captchaId.value = ''; },
  });
});

async function submit() {
  if (!captchaId.value || busy.value) return;
  busy.value = true;
  message.value = '';
  try {
    const response = await fetch('/api/protected-action', {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({ captchaId: captchaId.value }),
    });
    if (!response.ok) throw new Error('请求未完成,请重新验证后重试');
    message.value = '操作已完成';
  } catch (error) {
    message.value = error.message;
  } finally {
    captchaId.value = '';
    captcha?.reset();
    busy.value = false;
  }
}
</script>

<template>
  <div id="BUMO_CAPTCHA"></div>
  <button :disabled="!captchaId || busy" @click="submit">
    {{ busy ? '提交中…' : '提交' }}
  </button>
  <p role="status">{{ message }}</p>
</template>

/api/protected-action 是你的业务接口,不是验证码平台的地址。如果前后端不同域名,需要在你自己的后端配置允许的跨域来源;涉及登录 Cookie 时,也要沿用应用原有的凭据和 CSRF 防护方案。不要为了让请求通过而开放任意来源。

提交结束后清空凭证并重置滑块,避免用户误把上一次的成功状态当成本次验证。按钮禁用用于减少重复点击,后端仍需自行保证业务幂等与限频。

第三步:Node.js 后端确认结果

下面函数使用支持全局 fetch 和 AbortSignal.timeout 的 Node.js 运行环境。三个环境变量仅在服务端设置:BUMO_CAPTCHA_API_KEY、BUMO_CAPTCHA_PRODUCT_ID、APP_ORIGIN。

export async function verifyCaptcha(captchaId) {
  if (typeof captchaId !== 'string' || !captchaId.trim()) return false;
  const key = process.env.BUMO_CAPTCHA_API_KEY;
  const productId = process.env.BUMO_CAPTCHA_PRODUCT_ID;
  const origin = process.env.APP_ORIGIN;
  if (!key || !productId || !origin) {
    throw new Error('验证码服务端配置不完整');
  }
  try {
    const response = await fetch(
      'https://captcha.bumo.cc/api/captcha/server/get-result',
      {
        method: 'POST',
        headers: {
          'Content-Type': 'application/json',
          authorization: `Bearer ${key}`,
          referer: origin,
          'x-id': productId,
        },
        body: JSON.stringify({ r: captchaId }),
        signal: AbortSignal.timeout(10000),
      },
    );
    if (!response.ok) return false;
    const result = await response.json();
    return result.success === true && result.data?.p === true;
  } catch {
    return false;
  }
}

在现有业务路由中先 await verifyCaptcha(requestBody.captchaId);结果为 false 时返回失败,只有 true 才进入业务操作。不要仅检查 HTTP 200,也不要只检查 JSON 的 success,检测是否通过还要看 data.p。

本例采用失败时拒绝的策略:网络超时、限流、异常响应都不放行。官方快速开始另有偏向可用性的降级示例,两者是不同的取舍。涉及收费资源、发短信或高风险操作时,不应把服务故障直接当作验证通过;应给用户明确重试入口,并由团队根据业务风险设计降级策略。

上线前用这五项验收

  1. 正常滑动后提交,后端确实调用校验服务,并在通过后才执行业务。
  2. 绕过页面,直接发送空 captchaId,业务操作不能执行。
  3. 校验返回 success: true 但 data.p: false,必须拒绝。
  4. 测试环境模拟校验超时或非 JSON 响应,页面可重试,后端不能自动放行。
  5. 浏览器源码与 Network 中找不到 API KEY,反复提交后滑块状态会重置。

本文代码已做本地模拟响应检查,未用真实付费凭据完成线上业务联调。接入后仍需用自己的产品 ID、白名单域名和后端 API KEY 跑通一次真实验证。

如果你还在判断验证码适合放在哪个入口,可以继续看注册防刷的处理顺序。已有 Vue 页面则可以从开通验证码试用开始,把前端回调和服务端校验接成一条完整链路。

相关阅读