rwadurian/backend/services/identity-service/src/api/controllers/totp.controller.ts

112 lines
2.9 KiB
TypeScript

import { Controller, Get, Post, Body, UseGuards } from '@nestjs/common';
import {
ApiTags,
ApiOperation,
ApiBearerAuth,
ApiResponse,
} from '@nestjs/swagger';
import { TotpService } from '@/application/services/totp.service';
import { CurrentUser, CurrentUserPayload } from '@/shared/decorators';
import { JwtAuthGuard } from '@/shared/guards/jwt-auth.guard';
class SetupTotpResponseDto {
secret: string;
qrCodeUrl: string;
manualEntryKey: string;
}
class TotpStatusResponseDto {
isEnabled: boolean;
isSetup: boolean;
enabledAt: Date | null;
}
class EnableTotpDto {
code: string;
}
class DisableTotpDto {
code: string;
}
class VerifyTotpDto {
code: string;
}
@ApiTags('TOTP')
@Controller('totp')
@UseGuards(JwtAuthGuard)
@ApiBearerAuth()
export class TotpController {
constructor(private readonly totpService: TotpService) {}
@Get('status')
@ApiOperation({
summary: '获取 TOTP 状态',
description: '查询当前用户的 TOTP 启用状态',
})
@ApiResponse({ status: 200, type: TotpStatusResponseDto })
async getStatus(
@CurrentUser() user: CurrentUserPayload,
): Promise<TotpStatusResponseDto> {
return this.totpService.getTotpStatus(BigInt(user.userId));
}
@Post('setup')
@ApiOperation({
summary: '设置 TOTP',
description: '生成 TOTP 密钥,返回二维码和手动输入密钥',
})
@ApiResponse({ status: 201, type: SetupTotpResponseDto })
async setup(
@CurrentUser() user: CurrentUserPayload,
): Promise<SetupTotpResponseDto> {
return this.totpService.setupTotp(BigInt(user.userId));
}
@Post('enable')
@ApiOperation({
summary: '启用 TOTP',
description: '验证码正确后启用 TOTP 二次验证',
})
@ApiResponse({ status: 200, description: 'TOTP 已启用' })
async enable(
@CurrentUser() user: CurrentUserPayload,
@Body() dto: EnableTotpDto,
): Promise<{ success: boolean; message: string }> {
await this.totpService.enableTotp(BigInt(user.userId), dto.code);
return { success: true, message: 'TOTP 已启用' };
}
@Post('disable')
@ApiOperation({
summary: '禁用 TOTP',
description: '验证码正确后禁用 TOTP 二次验证',
})
@ApiResponse({ status: 200, description: 'TOTP 已禁用' })
async disable(
@CurrentUser() user: CurrentUserPayload,
@Body() dto: DisableTotpDto,
): Promise<{ success: boolean; message: string }> {
await this.totpService.disableTotp(BigInt(user.userId), dto.code);
return { success: true, message: 'TOTP 已禁用' };
}
@Post('verify')
@ApiOperation({
summary: '验证 TOTP',
description: '验证 TOTP 验证码是否正确',
})
@ApiResponse({ status: 200, description: '验证结果' })
async verify(
@CurrentUser() user: CurrentUserPayload,
@Body() dto: VerifyTotpDto,
): Promise<{ valid: boolean }> {
const valid = await this.totpService.verifyTotp(
BigInt(user.userId),
dto.code,
);
return { valid };
}
}