权限管理
About 2 min
详见:权限
权限是指确定一个用户可以做什么的过程。例如,管理员用户可以创建、编辑和删除文章,非管理员用户只能授权阅读文章
1. 更新数据库模型
我们先更新数据库中的数据模型:
// schema.prisma
model user {
id Int @id @default(autoincrement()) @db.UnsignedInt
name String @unique
password String
role String?
}
运行命令:
npx prisma migrate dev
2. 基本的RBAC实现
这里我们基于角色的访问控制(RBAC)实现,首先我们在auth文件夹中创建一个enums文件夹,然后创建一个枚举来表示系统中的角色:
// role.enum.ts
export enum Role {
User = 'user',
Admin = 'admin',
}
我们可以在auth文件夹下创建一个decorator
文件夹,在文件夹中创建一个@Roles()
的装饰器,该装饰器允许某些角色拥有获取特定资源访问权
// roles.decorator.ts
import { SetMetadata } from '@nestjs/common';
import { Role } from '../enums/role.enum';
export const ROLES_KEY = 'roles';
export const Roles = (...roles: Role[]) => SetMetadata(ROLES_KEY, roles);
现在可以将@Roles()
装饰器应用于任何控制器
例如:
// article.controller.ts
import {
Controller,
Get,
Post,
Body,
Patch,
Param,
Delete,
} from '@nestjs/common';
import { ArticleService } from './article.service';
import { CreateArticleDto } from './dto/create-article.dto';
import { UpdateArticleDto } from './dto/update-article.dto';
import { Roles } from 'src/auth/decorator/roles.decorator';
import { Role } from 'src/auth/enums/role.enum';
@Controller('article')
export class ArticleController {
constructor(private readonly articleService: ArticleService) {}
@Post()
@Roles(Role.Admin) // 使用装饰器
create(@Body() createArticleDto: CreateArticleDto) {
return this.articleService.create(createArticleDto);
}
@Get()
findAll() {
return this.articleService.findAll();
}
@Get(':id')
findOne(@Param('id') id: string) {
return this.articleService.findOne(+id);
}
@Patch(':id')
update(@Param('id') id: string, @Body() updateArticleDto: UpdateArticleDto) {
return this.articleService.update(+id, updateArticleDto);
}
@Delete(':id')
remove(@Param('id') id: string) {
return this.articleService.remove(+id);
}
}
创建一个RolesGuard
类来比较当前用户拥有的角色和当前路径需要的角色。为了获取路径的角色(自定义元数据),我们使用Reflector
辅助类,这是个@nestjs/core
提供的一个开箱即用的类
在auth文件夹下创建roles.guard.ts
文件
// roles.guard.ts
import { Injectable, CanActivate, ExecutionContext } from '@nestjs/common';
import { Reflector } from '@nestjs/core';
import { Role } from './enums/role.enum';
import { ROLES_KEY } from './decorator/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));
}
}
最后,请确保注册 RolesGuard
,例如在控制器级别或全局级别:
providers: [
{
provide: APP_GUARD,
useClass: RolesGuard,
},
],
例:
// app.module.ts
import { Module } from '@nestjs/common';
import { AppController } from './app.controller';
import { AppService } from './app.service';
import { AuthModule } from './auth/auth.module';
import { PrismaService } from './prisma/prisma.service';
import { PrismaModule } from './prisma/prisma.module';
import { ArticleModule } from './article/article.module';
import { APP_GUARD } from '@nestjs/core';
import { JwtAuthGuard } from './auth/jwt-auth.guard';
import { RolesGuard } from './auth/roles.guard';
@Module({
imports: [AuthModule, PrismaModule, ArticleModule],
controllers: [AppController],
providers: [
AppService,
PrismaService,
{
provide: APP_GUARD,
useClass: JwtAuthGuard,
},
{
provide: APP_GUARD,
useClass: RolesGuard,
},
],
})
export class AppModule {}
此时只有管理员才可以增加文章