perf: 登录注册、找回密码都支持极验验证码和图片验证码

This commit is contained in:
xiaojunnuo
2025-09-13 23:01:14 +08:00
parent 50f92f55e2
commit 7bdde68ece
29 changed files with 446 additions and 390 deletions
@@ -1,4 +1,4 @@
export interface ICaptchaAddon{
onValidate(data?:any):Promise<any>;
getClientParams():Promise<any>;
getCaptcha():Promise<any>;
}
@@ -1,6 +1,7 @@
import { AddonInput, BaseAddon, IsAddon } from "@certd/lib-server";
import crypto from 'crypto';
import crypto from "crypto";
import { ICaptchaAddon } from "../api.js";
@IsAddon({
addonType:"captcha",
name: 'geetest',
@@ -8,6 +9,7 @@ import { ICaptchaAddon } from "../api.js";
desc: '',
})
export class GeeTestCaptcha extends BaseAddon implements ICaptchaAddon{
@AddonInput({
title: 'captchaId',
component: {
@@ -28,7 +30,9 @@ export class GeeTestCaptcha extends BaseAddon implements ICaptchaAddon{
async onValidate(data?:any) {
if (!data) {
return false
}
// geetest 服务地址
// geetest server url
const API_SERVER = "http://gcaptcha4.geetest.com";
@@ -107,11 +111,10 @@ export class GeeTestCaptcha extends BaseAddon implements ICaptchaAddon{
return result;
}
async getClientParams(): Promise<any> {
async getCaptcha(): Promise<any> {
return {
captchaId: this.captchaId,
}
}
}
@@ -1,6 +1,8 @@
import { AddonInput, BaseAddon, IsAddon } from "@certd/lib-server";
import crypto from 'crypto';
import { BaseAddon, IsAddon } from "@certd/lib-server";
import { ICaptchaAddon } from "../api.js";
import { cache } from "@certd/basic";
import { nanoid } from "nanoid";
@IsAddon({
addonType:"captcha",
name: 'image',
@@ -9,42 +11,45 @@ import { ICaptchaAddon } from "../api.js";
})
export class ImageCaptcha extends BaseAddon implements ICaptchaAddon{
async onValidate(data?:any) {
}
// 生成签名
// Generate signature
hmac_sha256_encode(value, key){
var hash = crypto.createHmac("sha256", key)
.update(value, 'utf8')
.digest('hex');
return hash;
}
// 发送post请求, 响应json数据如:{"result": "success", "reason": "", "captcha_args": {}}
// Send a post request and respond to JSON data, such as: {result ":" success "," reason ":" "," captcha_args ": {}}
async doRequest(datas, url){
var options = {
url: url,
method: "POST",
params: datas,
timeout: 5000
};
const result = await this.ctx.http.request(options);
return result;
}
async getClientParams(): Promise<any> {
return {
captchaId: this.captchaId,
if (!data) {
return false;
}
return await this.checkCaptcha(data.randomStr, data.imageCode)
}
async getCaptchaText(randomStr:string) {
return cache.get('imgCode:' + randomStr);
}
async removeCaptcha(randomStr:string) {
cache.delete('imgCode:' + randomStr);
}
async checkCaptcha(randomStr: string, userCaptcha: string) {
const code = await this.getCaptchaText(randomStr);
if (code == null) {
throw new Error('验证码已过期');
}
if (code.toLowerCase() !== userCaptcha?.toLowerCase()) {
throw new Error('验证码不正确');
}
await this.removeCaptcha(randomStr);
return true;
}
async getCaptcha(): Promise<any> {
const svgCaptcha = await import('svg-captcha');
const c = svgCaptcha.create();
//{data: '<svg.../svg>', text: 'abcd'}
const imgCode = c.text; // = RandomUtil.randomStr(4, true);
const randomStr = nanoid(10)
cache.set('imgCode:' + randomStr, imgCode, {
ttl: 2 * 60 * 1000, //过期时间 2分钟
})
return {
randomStr: randomStr,
imageData: c.data,
}
}
}
@@ -1 +1,2 @@
export * from './geetest/index.js';
export * from './image/index.js';