From 1e2d269ec136e1dc011c5acc4e1cc46a819a76e5 Mon Sep 17 00:00:00 2001 From: tone Date: Thu, 18 Dec 2025 21:51:22 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20=E5=90=8E=E7=AB=AF=E4=BF=AE=E5=A4=8Dpass?= =?UTF-8?q?key=E6=B3=A8=E5=86=8C=E6=97=B6challenge=E4=B8=8D=E5=8C=B9?= =?UTF-8?q?=E9=85=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/backend/src/auth/dto/passkey-register.dto.ts | 4 +++- apps/backend/src/auth/service/passkey.service.ts | 15 ++++++++++----- 2 files changed, 13 insertions(+), 6 deletions(-) diff --git a/apps/backend/src/auth/dto/passkey-register.dto.ts b/apps/backend/src/auth/dto/passkey-register.dto.ts index 95869bb..7740d2e 100644 --- a/apps/backend/src/auth/dto/passkey-register.dto.ts +++ b/apps/backend/src/auth/dto/passkey-register.dto.ts @@ -1,7 +1,9 @@ -import { IsString } from "class-validator"; +import { IsObject, IsString } from "class-validator"; export class PasskeyRegisterDto { + @IsObject() credentialResponse: any; + @IsString({ message: '通行证名称只能是字符串' }) name: string; } \ No newline at end of file diff --git a/apps/backend/src/auth/service/passkey.service.ts b/apps/backend/src/auth/service/passkey.service.ts index 1bf5f4f..06217ff 100644 --- a/apps/backend/src/auth/service/passkey.service.ts +++ b/apps/backend/src/auth/service/passkey.service.ts @@ -3,7 +3,7 @@ import { InjectRepository } from "@nestjs/typeorm"; import { PasskeyCredential } from "../entity/passkey-credential.entity"; import { Repository } from "typeorm"; import { User } from "src/user/entities/user.entity"; -import crypto from 'crypto'; +import { randomBytes } from 'crypto'; import { generateAuthenticationOptions, GenerateAuthenticationOptionsOpts, generateRegistrationOptions, GenerateRegistrationOptionsOpts, VerifiedAuthenticationResponse, VerifiedRegistrationResponse, verifyAuthenticationResponse, verifyRegistrationResponse } from "@simplewebauthn/server"; @@ -91,14 +91,17 @@ export class PasskeyService implements OnModuleDestroy { authenticationChallenges.stopCleanup(); } + private generateChallenge(length: number = 32): string { + return randomBytes(length).toString('base64'); + } + async getRegistrationOptions(userId: string) { const user = await this.userRepository.findOneBy({ userId }); if (!user) { throw new NotFoundException('用户不存在'); } - const challenge = crypto.randomBytes(32).toString('base64url'); - registrationChallenges.set(userId, challenge); + const challenge = this.generateChallenge(); const opts: GenerateRegistrationOptionsOpts = { rpName: this.rpName, @@ -115,7 +118,9 @@ export class PasskeyService implements OnModuleDestroy { timeout: 60000, }; - return generateRegistrationOptions(opts); + const options = await generateRegistrationOptions(opts); + registrationChallenges.set(userId, options.challenge) + return options; } async register(userId: string, credentialResponse: any, name: string): Promise { @@ -163,7 +168,7 @@ export class PasskeyService implements OnModuleDestroy { } async getAuthenticationOptions(sessionId: string) { - const challenge = crypto.randomBytes(32).toString('base64url'); + const challenge = this.generateChallenge(); authenticationChallenges.set(sessionId, challenge); const opts: GenerateAuthenticationOptionsOpts = {