feat: 调整项目层级

This commit is contained in:
2024-11-27 14:30:20 +08:00
parent 5eb78c35c2
commit b02e2d2160
43 changed files with 17 additions and 12 deletions

View File

@@ -0,0 +1,30 @@
import { Controller, Post, Body, Param } from '@nestjs/common';
import { AuthService } from './auth.service';
import { AuthDto } from './dto/auth.dto';
import { SkipAuth } from '@/common/decorators/skip-auth.decorator';
import { UserRoleDto } from './dto/user-role.dto';
import { RolePermissionDto } from './dto/role-permission.dto';
@Controller()
export class AuthController {
constructor(private readonly authService: AuthService) {}
// 用户登录
@Post('login')
@SkipAuth()
signIn(@Body() authDto: AuthDto) {
return this.authService.signIn(authDto);
}
// 授权用户角色
@Post('userRole/:id')
grantUserRole(@Param('id') id: string, @Body() dto: UserRoleDto) {
return this.authService.grantUserRole(+id, dto);
}
// 授权角色权限
@Post('rolePermission/:id')
grantRolePermission(@Param('id') id: string, @Body() dto: RolePermissionDto) {
return this.authService.grantRolePermission(+id, dto);
}
}

View File

@@ -0,0 +1,26 @@
import { Module } from '@nestjs/common';
import { AuthService } from './auth.service';
import { AuthController } from './auth.controller';
import { UserModule } from '../user/user.module';
import { JwtModule } from '@nestjs/jwt';
import { ConfigModule, ConfigService } from '@nestjs/config';
@Module({
imports: [
UserModule,
JwtModule.registerAsync({
imports: [ConfigModule],
inject: [ConfigService],
global: true,
useFactory: async (config: ConfigService) => {
return {
secret: config.get('jwt.secret'),
signOptions: { expiresIn: config.get('jwt.expiresIn') },
};
},
}),
],
controllers: [AuthController],
providers: [AuthService],
})
export class AuthModule {}

View File

@@ -0,0 +1,136 @@
import {
ForbiddenException,
HttpException,
HttpStatus,
Inject,
Injectable,
UnauthorizedException,
} from '@nestjs/common';
import { JwtService } from '@nestjs/jwt';
import { AuthDto } from './dto/auth.dto';
import * as bcrypt from 'bcryptjs';
import { PrismaService } from '@/prisma/prisma.service';
import { UserRoleDto } from './dto/user-role.dto';
import { RolePermissionDto } from './dto/role-permission.dto';
import { RedisGroup } from '@/common/enum';
import { ConfigService } from '@nestjs/config';
import { Cache, CACHE_MANAGER } from '@nestjs/cache-manager';
import { nanoid } from 'nanoid';
@Injectable()
export class AuthService {
constructor(
private readonly jwtService: JwtService,
private readonly prisma: PrismaService,
private readonly configService: ConfigService,
@Inject(CACHE_MANAGER) private cacheService: Cache,
) {}
// 登录
async signIn({ account, password }: AuthDto) {
const user = await this.prisma.sysUser.findUnique({
where: {
account,
},
});
if (!user) {
throw new UnauthorizedException('账号或密码错误!');
}
const pass = await bcrypt.hash(password, user.passwordSalt);
if (user?.password !== pass) {
throw new UnauthorizedException('账号或密码错误!');
}
if (user.status === 0) {
throw new ForbiddenException('此账户已被禁用!');
}
const jti = nanoid();
const payload = { sub: user.id, account: user.account, jti };
const accessToken = await this.jwtService.signAsync(payload);
await this.cacheService.set(
`${RedisGroup.JwtJti}:${user.id}:${jti}`,
user.id,
this.configService.get('jwt.redisExpiresIn'),
);
return { accessToken };
}
async grantUserRole(id: number, { roleIds }: UserRoleDto) {
const user = await this.prisma.sysUser.findUnique({
where: { id },
});
if (!user) throw new HttpException('用户不存在!', HttpStatus.NOT_FOUND);
// 查询所有角色id
const allRoles = await this.prisma.sysRole.findMany({
select: { id: true },
});
const allRoleIds = allRoles.map((item) => item.id);
const isContain = roleIds.every((item) => allRoleIds.includes(item));
if (!isContain)
throw new HttpException(
'出现不存在的角色id,请检查传入的roleIds',
HttpStatus.BAD_REQUEST,
);
const data = roleIds.map((item) => ({
userId: id,
roleId: item,
}));
await this.prisma.$transaction(async (prisma) => {
await prisma.sysUserRole.deleteMany({
where: { userId: id },
});
await prisma.sysUserRole.createMany({ data });
});
}
async grantRolePermission(id: number, { permissionIds }: RolePermissionDto) {
const role = await this.prisma.sysRole.findUnique({
where: { id },
});
if (!role)
throw new HttpException('角色信息不存在!', HttpStatus.NOT_FOUND);
// 查询所有权限
const allPermission = await this.prisma.sysPermission.findMany({
select: { id: true },
});
const allPermissionIds = allPermission.map((item) => item.id);
// 判断传入的id是否都存在于数据库中
const isContain = permissionIds.every((item) =>
allPermissionIds.includes(item),
);
if (!isContain)
throw new HttpException(
'出现不存在的权限id,请检查传入的permissionIds',
HttpStatus.BAD_REQUEST,
);
const data = permissionIds.map((permissionId) => ({
roleId: id,
permissionId,
}));
await this.prisma.$transaction([
this.prisma.sysRolePermission.deleteMany({
where: { permissionId: { in: permissionIds } },
}),
this.prisma.sysRolePermission.createMany({ data }),
]);
}
}

View File

@@ -0,0 +1,7 @@
import { CreateUserDto } from '@/modules/system/user/dto/create-user.dto';
import { PickType } from '@nestjs/mapped-types';
export class AuthDto extends PickType(CreateUserDto, [
'account',
'password',
] as const) {}

View File

@@ -0,0 +1,8 @@
import { ArrayUnique, IsInt, IsNotEmpty } from 'class-validator';
export class RolePermissionDto {
@IsNotEmpty()
@IsInt({ each: true })
@ArrayUnique()
permissionIds: number[];
}

View File

@@ -0,0 +1,8 @@
import { ArrayUnique, IsInt, IsNotEmpty } from 'class-validator';
export class UserRoleDto {
@IsNotEmpty()
@IsInt({ each: true })
@ArrayUnique()
roleIds: number[];
}

View File

@@ -0,0 +1,22 @@
import { Injectable, CanActivate, ExecutionContext } from '@nestjs/common';
import { Reflector } from '@nestjs/core';
import { Role } from '@/common/enum';
import { ROLES_KEY } from '@/common/decorators/roles.decorator';
@Injectable()
export class RolesGuard implements CanActivate {
constructor(private reflector: Reflector) {}
canActivate(context: ExecutionContext): boolean {
const requiredRoles = this.reflector.getAllAndOverride<Role[]>(ROLES_KEY, [
context.getHandler(),
context.getClass(),
]);
if (!requiredRoles) {
return true;
}
const { user } = context.switchToHttp().getRequest();
return requiredRoles.some((role) => user.roles?.includes(role));
}
}