feat: 后端调整登陆逻辑

This commit is contained in:
2025-12-16 22:48:51 +08:00
parent b235ca8a6e
commit 70517058ae
13 changed files with 305 additions and 194 deletions

View File

@@ -1,12 +1,12 @@
import { createHash } from 'crypto';
import { BadRequestException, Injectable } from '@nestjs/common';
import { LoginDto } from './dto/login.dto';
import { UserService } from 'src/user/user.service';
import { User } from 'src/user/entities/user.entity';
import { JwtService } from '@nestjs/jwt';
import { UserSessionService } from 'src/user/services/user-session.service';
import { v4 as uuidv4 } from 'uuid';
import { VerificationService } from 'src/verification/verification.service';
import { BusinessException } from 'src/common/exceptions/business.exception';
import { ErrorCode } from 'src/common/constants/error-codes';
@Injectable()
export class AuthService {
@@ -15,40 +15,49 @@ export class AuthService {
private readonly jwtService: JwtService,
private readonly userSessionService: UserSessionService,
private readonly verificationService: VerificationService,
) {}
) { }
async loginWithPassword(loginDto: LoginDto) {
const { account, password } = loginDto;
// 依次使用邮箱登录、手机号、账号
async loginWithPassword(identifier: string, password: string) {
// 依次使用邮箱、手机号、账号登陆(防止有大聪明给账号改成别人的邮箱或手机号)
const user = await this.userService.findOne(
[{ email: account }, { phone: account }, { username: account }],
[{ email: identifier }, { phone: identifier }, { username: identifier }],
{
withDeleted: true,
},
);
if (user && user.deletedAt !== null) {
throw new BadRequestException('该账号注销中');
throw new BusinessException({
message: '该账号注销中',
code: ErrorCode.USER_ACCOUNT_DEACTIVATED,
});
}
if (user === null || !user.password_hash || !user.salt) {
throw new BadRequestException('账户或密码错误');
throw new BusinessException({
message: '账户或密码错误',
code: ErrorCode.AUTH_INVALID_CREDENTIALS
});
}
// 判断密码是否正确
const hashedPassword = this.hashPassword(password, user.salt);
if (hashedPassword !== user.password_hash) {
throw new BadRequestException('账户或密码错误');
throw new BusinessException({
message: '账户或密码错误',
code: ErrorCode.AUTH_INVALID_CREDENTIALS
});
}
// 登录成功颁发token
return {
token: await this.generateToken(user),
userId: user.userId,
};
}
async loginWithPhone(loginDto: LoginDto) {
const { phone, code } = loginDto;
async loginWithPhone(data: { phone: string; code: string; }) {
const { phone, code } = data;
// 先判断验证码是否正确
const isValid = this.verificationService.verifyPhoneCode(
phone,
@@ -90,65 +99,21 @@ export class AuthService {
};
}
async loginWithEmail(loginDto: LoginDto) {
const { email, code } = loginDto;
// 先判断验证码是否正确
const isValid = this.verificationService.verifyEmailCode(
email,
code,
'login',
);
switch (isValid) {
case 0:
break;
case -1:
throw new BadRequestException('验证码已过期,请重新获取');
case -2:
throw new BadRequestException('验证码错误');
case -3:
throw new BadRequestException('验证码已失效,请重新获取');
default:
throw new BadRequestException('验证码错误,请稍后再试');
}
// 判断用户是否存在,若不存在则进行注册
let user = await this.userService.findOne({ email }, { withDeleted: true });
if (user && user.deletedAt !== null) {
throw new BadRequestException('该账号注销中,请使用其他邮箱');
}
if (!user) {
// 执行注册操作
user = await this.userService.create({ email: email });
}
if (!user || !user.userId) {
// 注册失败或用户信息错误
throw new BadRequestException('请求失败,请稍后再试');
}
// 登录颁发token
return {
token: await this.generateToken(user),
};
}
private hashPassword(password: string, salt: string): string {
return createHash('sha256').update(`${password}${salt}`).digest('hex');
}
private async generateToken(user: User) {
// 存储
const sessionRes = await this.userSessionService.createSession(
user.userId,
);
const payload = {
userId: user.userId,
sessionId: uuidv4(),
sessionId: sessionRes.sessionId,
};
// 存储
await this.userSessionService.createSession(
payload.userId,
payload.sessionId,
);
// 颁发token
return this.jwtService.sign(payload);
}