diff --git a/packages/app/src/utils/auth.ts b/packages/app/src/utils/auth.ts index 0b44e83..354d0d6 100644 --- a/packages/app/src/utils/auth.ts +++ b/packages/app/src/utils/auth.ts @@ -8,12 +8,34 @@ interface LoginResponse { export async function wxLogin(): Promise { return new Promise((resolve, reject) => { + // Step 1:静默登录,获取 code uni.login({ provider: 'weixin', success: async (loginRes) => { try { + // Step 2: 获取用户微信头像和昵称 + let nickname: string | undefined + let avatarUrl: string | undefined + await new Promise((res) => { + uni.getUserProfile({ + desc: '用于完善个人资料', + success: (profileRes) => { + nickname = profileRes.userInfo.nickName + avatarUrl = profileRes.userInfo.avatarUrl + res() + }, + fail: () => { + // 用户拒绝授权,仍可继续登录 + res() + }, + }) + }) + + // Step 3: 发送登录请求 const result = await post('/auth/login', { code: loginRes.code, + nickname, + avatarUrl, }) uni.setStorageSync('token', result.token) resolve(result) diff --git a/packages/server/src/auth/auth.controller.ts b/packages/server/src/auth/auth.controller.ts index d6f97f7..3655c15 100644 --- a/packages/server/src/auth/auth.controller.ts +++ b/packages/server/src/auth/auth.controller.ts @@ -25,7 +25,11 @@ export class AuthController { @Post('login') @HttpCode(HttpStatus.OK) async login(@Body() loginDto: LoginDto): Promise<{ token: string; user: User }> { - return this.authService.login(loginDto.code) + return this.authService.login( + loginDto.code, + loginDto.nickname, + loginDto.avatarUrl, + ) } @Post('phone') diff --git a/packages/server/src/auth/auth.module.ts b/packages/server/src/auth/auth.module.ts index a27a374..4bac297 100644 --- a/packages/server/src/auth/auth.module.ts +++ b/packages/server/src/auth/auth.module.ts @@ -2,7 +2,7 @@ import { Module } from '@nestjs/common' import { PassportModule } from '@nestjs/passport' import { JwtModule } from '@nestjs/jwt' import { ConfigModule, ConfigService } from '@nestjs/config' -import { AuthService } from './auth.service' +import { AuthService, RANDOM_FN_TOKEN } from './auth.service' import { AuthController } from './auth.controller' import { WechatService } from './wechat.service' import { JwtStrategy } from './jwt.strategy' @@ -22,7 +22,7 @@ import { RolesGuard } from './roles.guard' }), ], controllers: [AuthController], - providers: [AuthService, WechatService, JwtStrategy, JwtAuthGuard, RolesGuard], + providers: [AuthService, WechatService, JwtStrategy, JwtAuthGuard, RolesGuard, { provide: RANDOM_FN_TOKEN, useValue: Math.random }], exports: [JwtStrategy, JwtAuthGuard, RolesGuard, AuthService], }) export class AuthModule {} diff --git a/packages/server/src/auth/auth.service.ts b/packages/server/src/auth/auth.service.ts index 8416dd5..431e979 100644 --- a/packages/server/src/auth/auth.service.ts +++ b/packages/server/src/auth/auth.service.ts @@ -57,7 +57,11 @@ export class AuthService { @Inject(RANDOM_FN_TOKEN) private readonly randomFn: () => number = Math.random, ) {} - async login(code: string): Promise { + async login( + code: string, + nickname?: string, + avatarUrl?: string, + ): Promise { const { openid, unionid, sessionKey } = await this.wechatService.code2Session(code) @@ -71,10 +75,23 @@ export class AuthService { data: { openid, ...(unionid !== undefined && { unionid }), - nickname: generateDefaultNickname(this.randomFn), + nickname: nickname || generateDefaultNickname(this.randomFn), + ...(avatarUrl && { avatarUrl }), }, })) + // Update avatar for existing users if new avatar is provided + if (existingUser && avatarUrl) { + const updated = await this.prisma.user.update({ + where: { id: existingUser.id }, + data: { avatarUrl, ...(nickname && { nickname }) }, + }) + sessionKeyStore.set(updated.id, sessionKey) + const payload: JwtPayload = { sub: updated.id, role: updated.role as UserRole } + const token = this.jwtService.sign(payload) + return { token, user: updated } + } + sessionKeyStore.set(user.id, sessionKey) const payload: JwtPayload = { sub: user.id, role: user.role as UserRole } diff --git a/packages/server/src/auth/dto/login.dto.ts b/packages/server/src/auth/dto/login.dto.ts index 78f83b9..d1da171 100644 --- a/packages/server/src/auth/dto/login.dto.ts +++ b/packages/server/src/auth/dto/login.dto.ts @@ -1,7 +1,15 @@ -import { IsString, IsNotEmpty } from 'class-validator' +import { IsString, IsNotEmpty, IsOptional } from 'class-validator' export class LoginDto { @IsString() @IsNotEmpty() code!: string + + @IsString() + @IsOptional() + nickname?: string + + @IsString() + @IsOptional() + avatarUrl?: string }