From dc16a616a571a5732fa10ef1d89487e667324e9d Mon Sep 17 00:00:00 2001 From: hailin Date: Sat, 27 Dec 2025 23:27:21 -0800 Subject: [PATCH] =?UTF-8?q?fix(identity-service):=20=E4=BF=AE=E5=A4=8D?= =?UTF-8?q?=E5=B9=B6=E5=8F=91auto-login=E8=AF=B7=E6=B1=82=E5=AF=BC?= =?UTF-8?q?=E8=87=B4=E7=9A=84=E5=94=AF=E4=B8=80=E7=BA=A6=E6=9D=9F=E5=86=B2?= =?UTF-8?q?=E7=AA=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 在创建新token前先撤销该设备的旧token - 使用upsert替代create避免并发时refresh_token_hash唯一约束冲突 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 --- .../src/application/services/token.service.ts | 23 +++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/backend/services/identity-service/src/application/services/token.service.ts b/backend/services/identity-service/src/application/services/token.service.ts index 03484c54..4c4a756f 100644 --- a/backend/services/identity-service/src/application/services/token.service.ts +++ b/backend/services/identity-service/src/application/services/token.service.ts @@ -47,8 +47,27 @@ export class TokenService { // Save refresh token hash const tokenHash = this.hashToken(refreshToken); - await this.prisma.deviceToken.create({ - data: { + + // 先撤销该设备的旧 token,避免唯一约束冲突 + await this.prisma.deviceToken.updateMany({ + where: { + userId: BigInt(payload.userId), + deviceId: payload.deviceId, + revokedAt: null, + }, + data: { revokedAt: new Date() }, + }); + + // 使用 upsert 避免并发请求导致的唯一约束冲突 + await this.prisma.deviceToken.upsert({ + where: { refreshTokenHash: tokenHash }, + update: { + userId: BigInt(payload.userId), + deviceId: payload.deviceId, + expiresAt: new Date(Date.now() + 30 * 24 * 60 * 60 * 1000), + revokedAt: null, + }, + create: { userId: BigInt(payload.userId), deviceId: payload.deviceId, refreshTokenHash: tokenHash,