feat: 后端也添加了写了一半的人机验证模块

This commit is contained in:
2025-12-17 20:31:23 +08:00
parent c9e49bb769
commit 54acad1671
9 changed files with 106 additions and 2 deletions

View File

@@ -12,6 +12,7 @@ import { BlogModule } from './blog/blog.module';
import { AdminModule } from './admin/admin.module';
import { OssModule } from './oss/oss.module';
import { ThrottlerModule } from '@nestjs/throttler';
import { CaptchaModule } from './captcha/captcha.module';
@Module({
imports: [
@@ -43,6 +44,7 @@ import { ThrottlerModule } from '@nestjs/throttler';
BlogModule,
AdminModule,
OssModule,
CaptchaModule,
],
controllers: [AppController],
providers: [AppService],

View File

@@ -0,0 +1,18 @@
import { Test, TestingModule } from '@nestjs/testing';
import { CaptchaController } from './captcha.controller';
describe('CaptchaController', () => {
let controller: CaptchaController;
beforeEach(async () => {
const module: TestingModule = await Test.createTestingModule({
controllers: [CaptchaController],
}).compile();
controller = module.get<CaptchaController>(CaptchaController);
});
it('should be defined', () => {
expect(controller).toBeDefined();
});
});

View File

@@ -0,0 +1,10 @@
import { Controller, Get } from '@nestjs/common';
import { GetCaptchaDto } from './dto/get-captcha.dto';
@Controller('captcha')
export class CaptchaController {
@Get()
async getCaptcha(dto: GetCaptchaDto) {
}
}

View File

@@ -0,0 +1,11 @@
import { Module } from '@nestjs/common';
import { CaptchaService } from './captcha.service';
import { CaptchaController } from './captcha.controller';
import { CaptchaRateLimitService } from './service/rate-limit';
@Module({
providers: [CaptchaService, CaptchaRateLimitService],
controllers: [CaptchaController],
imports: [],
})
export class CaptchaModule { }

View File

@@ -0,0 +1,18 @@
import { Test, TestingModule } from '@nestjs/testing';
import { CaptchaService } from './captcha.service';
describe('CaptchaService', () => {
let service: CaptchaService;
beforeEach(async () => {
const module: TestingModule = await Test.createTestingModule({
providers: [CaptchaService],
}).compile();
service = module.get<CaptchaService>(CaptchaService);
});
it('should be defined', () => {
expect(service).toBeDefined();
});
});

View File

@@ -0,0 +1,27 @@
import { Injectable } from '@nestjs/common';
import { ErrorCode } from 'src/common/constants/error-codes';
import { BusinessException } from 'src/common/exceptions/business.exception';
export enum CaptchaContext {
SEND_SMS = 'send_sms',
PASSKEY = 'passkey',
}
@Injectable()
export class CaptchaService {
public async generate(context: CaptchaContext, ip: string, userId?: string) {
await this.checkRateLimit(ip, context)
}
public async verify(token: string, ip: string, userId?: string) {
}
private async checkRateLimit(ip: string, context: CaptchaContext) {
/** @todo */
throw new BusinessException({
code: ErrorCode.CAPTCHA_RARE_LIMIT,
message: '服务器处理不过来了,过会儿再试试吧',
});
}
}

View File

@@ -0,0 +1,16 @@
import { IsEnum, IsOptional, IsUUID } from "class-validator";
export enum CaptchaContext {
SEND_SMS = 'send_sms',
PASSKEY = 'passkey',
}
export class GetCaptchaDto {
@IsEnum(CaptchaContext, { message: '无效的context' })
context: string;
@IsOptional()
@IsUUID('4', { message: 'userId不合法' })
userId?: string;
}

View File

@@ -0,0 +1,3 @@
export class CaptchaRateLimitService {
}

View File

@@ -29,8 +29,7 @@ export const ErrorCode = {
BLOG_PERMISSION_DENIED: -3002,
// 验证模块4000 ~ 4999
VERIFICATION_CODE_EXPIRED: -4001,
VERIFICATION_CODE_INCORRECT: -4002,
CAPTCHA_RARE_LIMIT: -4001,
// 通知模块5000 ~ 5999
NOTIFICATION_SEND_FAILED: -5001,