立即注册找回密码

QQ登录

只需一步,快速开始

微信登录

微信扫一扫,快速登录

手机动态码快速登录

手机号快速注册登录

搜索

图文播报

查看: 128|回复: 0

[分享] 干掉图形验证码!基于PoW的Cap验证码集成指南

[复制链接]
发表于 2025-6-24 23:12 | 显示全部楼层 |阅读模式

登陆有奖并可浏览互动!

您需要 登录 才可以下载或查看,没有账号?立即注册 微信登录 手机动态码快速登录

×
Cap 是什么

A modern, lightning-quick PoW captcha
一种现代的、闪电般快速的工作量证明验证码
Cap is a lightweight, modern open-source CAPTCHA alternative using proof-of-work
Cap 是一款轻量级、现代化的开源验证码替代方案,采用工作量证明机制。
与传统验证码不同,Cap:

  • 速度快且不干扰用户
  • 不使用跟踪技术或 cookie
  • 使用工作量证明而非干扰性谜题
  • 完全可访问且可自行托管
Cap 主要由小部件(可以以不可见的方式使用)和服务器(你也可以使用独立服务器)组成。另外,它还支持机器对机器通信,并且有一个类似于 Cloudflare 的检查点中间件。
文档地址:https://capjs.js.org/
github:https://github.com/tiagorangel1/cap
客户端

以在 Vue3 + ElementPlus 中使用为例
在 index.html 引入 Cap widget:
生产环境请引入固定版本
<script src=&#34;https://cdn.jsdelivr.net/npm/@cap.js/widget&#34;></script>
在 ElForm 中使用组件:
<el-form-item prop=&#34;code&#34;>
  <cap-widget
    id=&#34;cap&#34;
    :data-cap-api-endpoint=&#34;capApi&#34;
    data-cap-i18n-verifying-label=&#34;验证中...&#34;
    data-cap-i18n-initial-state=&#34;点击验证&#34;
    data-cap-i18n-solved-label=&#34;验证通过&#34;
    data-cap-i18n-error-label=&#34;验证失败,请重试&#34;
  ></cap-widget>
</el-form-item>其中data-cap-api-endpoint为服务端验证 URL 我这里设置为:
const capApi = ref(`${import.meta.env.VITE_API_URL}/admin/sys/login/`);data-cap-i18n开头的几个选项为国际化设置。
设置表单,以及校验规则:
import { type FormInstance, type FormRules } from &#34;element-plus&#34;;

const formRef = ref<FormInstance>();

let formData = reactive<
  paths[&#34;/admin/sys/login&#34;][&#34;post&#34;][&#34;requestBody&#34;][&#34;content&#34;][&#34;application/json&#34;]
>({
  username: &#34;&#34;,
  password: &#34;&#34;,
  code: &#34;&#34;,
});

const rules = reactive<FormRules<typeof formData>>({
  username: [{ required: true, message: &#34;请输入用户名&#34; }],
  password: [{ required: true, message: &#34;请输入密码&#34; }],
  code: [{ required: true, message: &#34;请点击验证&#34; }],
});监听 Cap 校验结果:
onMounted(() => {
  const widget = document.querySelector(&#34;#cap&#34;);

  widget?.addEventListener(&#34;solve&#34;, function (e: any) {
    formData.code = e.detail.token;
  });
});表单校验及提交不在赘述


服务端

以在 Nestjs 中使用为例
安装 @cap.js/server
npm i @cap.js/server在 Service 中创建 Cap 实例:
import Cap from &#34;@cap.js/server&#34;;
import { InjectRepository } from &#34;@nestjs/typeorm&#34;;

@Injectable()
export class LoginService {
  // ...
  cap: Cap = new Cap({ tokens_store_path: &#34;.data/tokensList.json&#34; });
  //...
}
Cap 默认使用内存和文件存储 token,你可以将noFSState设置为true,仅使用内存存储 token。
你可以将此与设置config.state结合使用,以使用诸如Redis之类来存储令牌。
可以参考这个 Pull requests
在 Controller 中创建接口:
import { BadRequestException, Body, Controller, Post } from &#34;@nestjs/common&#34;;
import { LoginService } from &#34;./login.service&#34;;

@Controller(&#34;login&#34;)
export class LoginController {
  constructor(private readonly loginService: LoginService) {}

  @Post(&#34;/challenge&#34;)
  async challenge() {
    return this.loginService.cap.createChallenge();
  }

  @Post(&#34;/redeem&#34;)
  async redeem(
    @Body() body: { token: string; solutions: Array<[string, string, string]> }
  ) {
    const { token, solutions } = body;
    if (!token || !solutions) {
      return new BadRequestException(&#34;人机验证失败&#34;);
    }
    return this.loginService.cap.redeemChallenge({ token, solutions });
  }
}当用户点击客户端 Cap 组件时,将请求/challenge和/redeem获取 token。





最后在登录接口的 Service 内添加 token 验证:
// ...
const result = await this.cap.validateToken(loginDto.code);
if (!result.success) {
  throw new BadRequestException(&#34;人机验证失败&#34;);
}
// ...结束啦

如果你想看这篇文章内的详细代码,可以查看 foolon admin 的登录功能:
github:https://github.com/LLcci/foolon-admin-monorepo
gitee:https://gitee.com/shangchehanyu_admin/foolon-admin-monorepo
如果你有任何想法,欢迎在评论区交流呀~


原文地址:https://zhuanlan.zhihu.com/p/1916878254624703223
楼主热帖
回复

使用道具 举报

发表回复

您需要登录后才可以回帖 登录 | 立即注册 微信登录 手机动态码快速登录

本版积分规则

关闭

官方推荐 上一条 /3 下一条

快速回复 返回列表 客服中心 搜索 官方QQ群 洽谈合作
快速回复返回顶部 返回列表