92 lines
2.5 KiB
TypeScript
92 lines
2.5 KiB
TypeScript
import { Injectable, UnauthorizedException } from '@nestjs/common';
|
|
import { JwtService } from '@nestjs/jwt';
|
|
import * as bcrypt from 'bcryptjs';
|
|
import { PrismaService } from '../../prisma/prisma.service';
|
|
|
|
@Injectable()
|
|
export class AuthService {
|
|
constructor(
|
|
private prisma: PrismaService,
|
|
private jwtService: JwtService,
|
|
) {}
|
|
|
|
async register(data: { phone?: string; email?: string; password: string; nickname?: string }) {
|
|
const passwordHash = await bcrypt.hash(data.password, 10);
|
|
const user = await this.prisma.user.create({
|
|
data: {
|
|
phone: data.phone,
|
|
email: data.email,
|
|
passwordHash,
|
|
nickname: data.nickname || data.phone || data.email?.split('@')[0],
|
|
},
|
|
});
|
|
return this.generateTokens(user.id);
|
|
}
|
|
|
|
async login(account: string, password: string) {
|
|
const user = await this.prisma.user.findFirst({
|
|
where: {
|
|
OR: [{ phone: account }, { email: account }],
|
|
deletedAt: null,
|
|
},
|
|
});
|
|
|
|
if (!user || !user.passwordHash) {
|
|
throw new UnauthorizedException('账号或密码错误');
|
|
}
|
|
|
|
const isValid = await bcrypt.compare(password, user.passwordHash);
|
|
if (!isValid) {
|
|
throw new UnauthorizedException('账号或密码错误');
|
|
}
|
|
|
|
await this.prisma.user.update({
|
|
where: { id: user.id },
|
|
data: { lastLoginAt: new Date() },
|
|
});
|
|
|
|
return this.generateTokens(user.id);
|
|
}
|
|
|
|
async refreshAccessToken(accessToken: string) {
|
|
try {
|
|
const payload = this.jwtService.verify(accessToken, { ignoreExpiration: true });
|
|
const user = await this.prisma.user.findUnique({
|
|
where: { id: payload.sub, deletedAt: null },
|
|
});
|
|
if (!user || user.status !== 'ACTIVE') {
|
|
throw new UnauthorizedException('用户不可用');
|
|
}
|
|
return this.generateTokens(user.id);
|
|
} catch {
|
|
throw new UnauthorizedException('Token 无效');
|
|
}
|
|
}
|
|
|
|
async getProfile(userId: number) {
|
|
return this.prisma.user.findUnique({
|
|
where: { id: userId },
|
|
select: {
|
|
id: true,
|
|
phone: true,
|
|
email: true,
|
|
nickname: true,
|
|
avatar: true,
|
|
status: true,
|
|
memberPlan: true,
|
|
memberExpire: true,
|
|
sandboxDaily: true,
|
|
createdAt: true,
|
|
},
|
|
});
|
|
}
|
|
|
|
private generateTokens(userId: number) {
|
|
const payload = { sub: userId };
|
|
return {
|
|
accessToken: this.jwtService.sign(payload, { expiresIn: '2h' }),
|
|
refreshToken: this.jwtService.sign(payload, { expiresIn: '7d' }),
|
|
};
|
|
}
|
|
}
|