74 lines
2.2 KiB
TypeScript
74 lines
2.2 KiB
TypeScript
import { Injectable, UnauthorizedException } from '@nestjs/common';
|
|
import { JwtService } from '@nestjs/jwt';
|
|
import { InjectRepository } from '@nestjs/typeorm';
|
|
import { Repository } from 'typeorm';
|
|
import * as bcrypt from 'bcrypt';
|
|
import { User } from '../user/user.entity';
|
|
import { LoginDto } from './dto/login.dto';
|
|
import { JwtPayload } from './interfaces/jwt-payload.interface';
|
|
import { LoginResponse } from './interfaces/login-response.interface';
|
|
|
|
@Injectable()
|
|
export class AuthService {
|
|
constructor(
|
|
@InjectRepository(User)
|
|
private readonly userRepository: Repository<User>,
|
|
private readonly jwtService: JwtService,
|
|
) {}
|
|
|
|
/**
|
|
* 用户登录
|
|
*/
|
|
async login(loginDto: LoginDto): Promise<LoginResponse> {
|
|
// 根据用户名或邮箱查找用户
|
|
const user = await this.userRepository.findOne({
|
|
where: [
|
|
{ username: loginDto.usernameOrEmail },
|
|
{ email: loginDto.usernameOrEmail },
|
|
],
|
|
});
|
|
|
|
if (!user) {
|
|
throw new UnauthorizedException('用户名或密码错误');
|
|
}
|
|
|
|
// 检查用户状态
|
|
if (user.status !== 'active') {
|
|
throw new UnauthorizedException('用户已被禁用');
|
|
}
|
|
|
|
// 验证密码
|
|
const isPasswordValid = await bcrypt.compare(
|
|
loginDto.password,
|
|
user.passwordHash,
|
|
);
|
|
|
|
if (!isPasswordValid) {
|
|
throw new UnauthorizedException('用户名或密码错误');
|
|
}
|
|
|
|
// 更新最后登录时间
|
|
user.lastLoginAt = new Date();
|
|
await this.userRepository.save(user);
|
|
|
|
// 生成 JWT token
|
|
const payload: JwtPayload = {
|
|
sub: user.userId,
|
|
username: user.username,
|
|
email: user.email,
|
|
role: user.role,
|
|
};
|
|
|
|
const accessToken = this.jwtService.sign(payload);
|
|
|
|
// 返回 token 和用户信息(排除密码)
|
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
const { passwordHash, ...userWithoutPassword } = user;
|
|
|
|
return {
|
|
accessToken,
|
|
user: userWithoutPassword,
|
|
};
|
|
}
|
|
}
|