feat: 支持自动续期

This commit is contained in:
richarjiang
2026-09-23 15:02:18 +08:00
parent 524bb9dcf3
commit a76afb19de
8 changed files with 92 additions and 15 deletions

View File

@@ -240,6 +240,23 @@ describe('AuthService', () => {
// ── bindPhone ──────────────────────────────────────────────────────────────
describe('renew', () => {
it('issues a fresh token using the current database role', async () => {
mockPrismaService.user.findUnique.mockResolvedValue({ ...mockUser, role: UserRole.ADMIN })
await expect(authService.renew(USER_ID)).resolves.toEqual({ token: JWT_TOKEN })
expect(mockJwtService.sign).toHaveBeenCalledWith({ sub: USER_ID, role: UserRole.ADMIN })
})
it('rejects deleted users', async () => {
mockPrismaService.user.findUnique.mockResolvedValue(null)
await expect(authService.renew(USER_ID)).rejects.toThrow(UnauthorizedException)
expect(mockJwtService.sign).not.toHaveBeenCalled()
})
})
describe('bindPhone', () => {
const encryptedData = 'encrypted_phone_data'
const iv = 'init_vector'

View File

@@ -34,6 +34,13 @@ export class AuthController {
)
}
@Post('renew')
@UseGuards(JwtAuthGuard)
@HttpCode(HttpStatus.OK)
renew(@Request() req: AuthenticatedRequest): Promise<{ token: string }> {
return this.authService.renew(req.user.sub)
}
@Post('phone')
@UseGuards(JwtAuthGuard)
@HttpCode(HttpStatus.OK)

View File

@@ -24,7 +24,7 @@ import { BodyPortraitModule } from '../body-portrait/body-portrait.module'
inject: [ConfigService],
useFactory: (configService: ConfigService) => ({
secret: configService.getOrThrow<string>('JWT_SECRET'),
signOptions: { expiresIn: '7d' },
signOptions: { expiresIn: '30d' },
}),
}),
],

View File

@@ -190,4 +190,10 @@ export class AuthService {
await this.portraitLifecycle?.onPhoneBound(userId)
return updated
}
async renew(userId: string): Promise<{ token: string }> {
const user = await this.prisma.user.findUnique({ where: { id: userId } })
if (!user) throw new UnauthorizedException('User no longer exists')
return { token: this.jwtService.sign({ sub: user.id, role: user.role as UserRole }) }
}
}