perf: 登录支持极验验证码

This commit is contained in:
xiaojunnuo
2025-09-11 23:47:05 +08:00
parent 65f34f1d31
commit 370db62bf0
22 changed files with 552 additions and 129 deletions
@@ -0,0 +1,83 @@
import { ALL, Body, Controller, Inject, Post, Provide, Query } from "@midwayjs/core";
import { AddonRequestHandleReq, AddonService, Constants } from "@certd/lib-server";
import { AddonController } from "../../user/addon/addon-controller.js";
@Provide()
@Controller('/api/sys/addon')
export class SysAddonController extends AddonController {
@Inject()
service2: AddonService;
getService(): AddonService {
return this.service2;
}
getUserId() {
// checkComm();
return 0;
}
@Post('/page', { summary: 'sys:settings:view' })
async page(@Body(ALL) body: any) {
return await super.page(body);
}
@Post('/list', { summary: 'sys:settings:view' })
async list(@Body(ALL) body: any) {
return await super.list(body);
}
@Post('/add', { summary: 'sys:settings:edit' })
async add(@Body(ALL) bean: any) {
return await super.add(bean);
}
@Post('/update', { summary: 'sys:settings:edit' })
async update(@Body(ALL) bean: any) {
return await super.update(bean);
}
@Post('/info', { summary: 'sys:settings:view' })
async info(@Query('id') id: number) {
return await super.info(id);
}
@Post('/delete', { summary: 'sys:settings:edit' })
async delete(@Query('id') id: number) {
return await super.delete(id);
}
@Post('/define', { summary: Constants.per.authOnly })
async define(@Query('type') type: string,@Query('addonType') addonType: string) {
return await super.define(type,addonType);
}
@Post('/getTypeDict', { summary: Constants.per.authOnly })
async getTypeDict(@Query('addonType') addonType: string) {
return await super.getTypeDict(addonType);
}
@Post('/simpleInfo', { summary: Constants.per.authOnly })
async simpleInfo(@Query('addonType') addonType: string,@Query('id') id: number) {
return await super.simpleInfo(addonType,id);
}
@Post('/getDefaultId', { summary: Constants.per.authOnly })
async getDefaultId(@Query('addonType') addonType: string) {
return await super.getDefaultId(addonType);
}
@Post('/setDefault', { summary: Constants.per.authOnly })
async setDefault(@Query('addonType') addonType: string,@Query('id') id: number) {
return await super.setDefault(addonType,id);
}
@Post('/options', { summary: Constants.per.authOnly })
async options(@Query('addonType') addonType: string) {
return await super.options(addonType);
}
@Post('/handle', { summary: Constants.per.authOnly })
async handle(@Body(ALL) body: AddonRequestHandleReq) {
return await super.handle(body);
}
}
@@ -1,18 +1,17 @@
import { ALL, Body, Controller, Inject, Post, Provide, Query } from '@midwayjs/core';
import { ALL, Body, Controller, Inject, Post, Provide, Query } from "@midwayjs/core";
import {
AccessGetter,
AddonDefine,
AddonRequestHandleReq,
AddonService,
Constants,
CrudController,
newAddon,
ValidateException
} from "@certd/lib-server";
import { AuthService } from '../../../modules/sys/authority/service/auth-service.js';
import { checkPlus } from '@certd/plus-core';
import { AddonService } from "@certd/lib-server";
import { AddonDefine } from "@certd/lib-server";
import { AccessRequestHandleReq, newAccess } from "@certd/pipeline";
import { AuthService } from "../../../modules/sys/authority/service/auth-service.js";
import { checkPlus } from "@certd/plus-core";
import { http, logger, utils } from "@certd/basic";
/**
* Addon
*/
@@ -1,8 +1,10 @@
import { ALL, Body, Controller, Inject, Post, Provide } from '@midwayjs/core';
import { LoginService } from '../../../modules/login/service/login-service.js';
import { BaseController, Constants, SysPublicSettings, SysSettingsService } from '@certd/lib-server';
import { CodeService } from '../../../modules/basic/service/code-service.js';
import { checkComm } from '@certd/plus-core';
import { ALL, Body, Controller, Inject, Post, Provide } from "@midwayjs/core";
import { LoginService } from "../../../modules/login/service/login-service.js";
import { AddonService, BaseController, Constants, SysPublicSettings, SysSettingsService } from "@certd/lib-server";
import { CodeService } from "../../../modules/basic/service/code-service.js";
import { checkComm } from "@certd/plus-core";
import { logger } from "@certd/basic";
import { ICaptchaAddon } from "../../../plugins/plugin-captcha/api.js";
/**
*/
@@ -16,14 +18,16 @@ export class LoginController extends BaseController {
@Inject()
sysSettingsService: SysSettingsService;
@Inject()
addonService: AddonService;
@Post('/login', { summary: Constants.per.guest })
public async login(
@Body(ALL)
user: any
body: any
) {
await this.loginService.doCaptchaValidate({form:user})
const token = await this.loginService.loginByPassword(user);
await this.loginService.doCaptchaValidate({form:body.captcha})
const token = await this.loginService.loginByPassword(body);
this.writeTokenCookie(token);
return this.ok(token);
}
@@ -79,4 +83,24 @@ export class LoginController extends BaseController {
});
return this.ok();
}
@Post('/captcha/getParams', { summary: Constants.per.guest })
async getCaptchaParams() {
const settings = await this.sysSettingsService.getPublicSettings()
if (settings.captchaEnabled) {
const addonId = settings.captchaAddonId;
const addon:ICaptchaAddon = await this.addonService.getAddonById(addonId,true,0)
if (!addon) {
logger.warn('验证码插件还未配置')
return this.ok({});
}
const params = await addon.getClientParams()
return this.ok(params);
}
return this.ok({});
}
}
@@ -105,19 +105,21 @@ export class LoginService {
const pubSetting = await this.sysSettingsService.getPublicSettings()
if (pubSetting.captchaEnabled) {
const prvSetting = await this.sysSettingsService.getPrivateSettings()
const addon = await this.addonService.getById(prvSetting.captchaAddonId,0)
const addon = await this.addonService.getById(pubSetting.captchaAddonId,0)
if (!addon) {
logger.warn('验证码插件还未配置,忽略验证码校验')
return true
}
if (addon.addonType !== pubSetting.captchaType) {
if (addon.define.name !== pubSetting.captchaType) {
logger.warn('验证码插件类型错误,忽略验证码校验')
return true
}
return await addon.onValidate(opts.form)
const res = await addon.onValidate(opts.form)
if (!res) {
throw new Error('验证码错误');
}
}
return true
@@ -0,0 +1,4 @@
export interface ICaptchaAddon{
onValidate(data?:any):Promise<any>;
getClientParams():Promise<any>;
}
@@ -1,12 +1,13 @@
import { AddonInput, BaseAddon, IsAddon } from "@certd/lib-server/dist/user/addon/api/index.js";
import crypto from 'crypto';
import { ICaptchaAddon } from "../api.js";
@IsAddon({
addonType:"captcha",
name: 'geetest',
title: '极验验证码',
desc: '',
})
export class GeeTestCaptcha extends BaseAddon {
export class GeeTestCaptcha extends BaseAddon implements ICaptchaAddon{
@AddonInput({
title: 'captchaId',
component: {
@@ -43,6 +44,9 @@ export class GeeTestCaptcha extends BaseAddon {
var captcha_output = data['captcha_output'];
var pass_token = data['pass_token'];
var gen_time = data['gen_time'];
if (!lot_number || !captcha_output || !pass_token || !gen_time) {
return false;
}
// 生成签名, 使用标准的hmac算法,使用用户当前完成验证的流水号lot_number作为原始消息message,使用客户验证私钥作为key
// 采用sha256散列算法将message和key进行单向散列生成最终的 “sign_token” 签名
@@ -78,8 +82,6 @@ export class GeeTestCaptcha extends BaseAddon {
this.ctx.logger.error("极验验证服务异常",e)
return true
}
}
// 生成签名
@@ -102,7 +104,13 @@ export class GeeTestCaptcha extends BaseAddon {
timeout: 5000
};
const result = await this.ctx.http.request(options);
return result.data;
return result;
}
async getClientParams(): Promise<any> {
return {
captchaId: this.captchaId,
}
}