nestjs自定义装饰器实践运用

概述

nestjs的装饰器很好用,于是想着自定义装饰器来实践下。
想到2个场景非常适合自定义装饰器。
一个是通过@User装饰器获取token下当前用户,
一个是通过@Permissions,进行角色权限的守卫校验。
那么实践一下呗

@User

对@user装饰器的实现,主要作用是能快速从token中快速拿到用户信息
user.decorator.ts

1
2
3
4
5
6
7
8
9
import { createParamDecorator, ExecutionContext } from '@nestjs/common';

export const User = createParamDecorator(
(data: string, ctx: ExecutionContext) => {
const request = ctx.switchToHttp().getRequest();
const user = request.user;
return data ? user && user[data] : user;
},
);

使用

1
2
3
4
@Get()
async findOne(@User() user: UserEntity) {
console.log(user);
}

1
2
3
4
@Get()
async findOne(@User('firstName') firstName: string) {
console.log(`Hello ${firstName}`);
}

@Permissions

permissions.decorator.ts

基于角色权限的装饰器实现,主要作用是进行增删改查操作的权限校验

1
2
3
4
5
6
7
8
9
10
11
// import { applyDecorators, SetMetadata } from '@nestjs/common';
// export const Permissions = (permissions: string) => SetMetadata('permissions', permissions);


import { applyDecorators, SetMetadata, UseGuards } from "@nestjs/common";
export function Permissions(permissions: string): Function {
// 可定义‘组合装饰器’
return applyDecorators(
SetMetadata('permissions', permissions)
)
}

拿个例子说下
获取用户列表v1/users接口增加@Permissions('sys:user:list')

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
import { Body, Controller, Delete, Get, Param, ParseIntPipe, Post, Put, Query, UseGuards, UsePipes, ValidationPipe } from '@nestjs/common';
import { AuthGuard } from '@nestjs/passport';
import { ApiBearerAuth, ApiCreatedResponse, ApiOkResponse, ApiOperation, ApiParam, ApiTags } from '@nestjs/swagger';
import { JwtAuthGuard } from 'src/common/guards/jwt-auth.guard';
import { RolesGuard } from 'src/common/guards/roles.guard';
import { Result } from 'src/common/utils/result';
import { QueryUserDto } from './dto/query.dto';
import { UserService } from './user.service';
import { Permissions } from 'src/common/decorator/permissions.decorator'

@ApiTags('用户相关')
@Controller('v1/users')
@ApiBearerAuth()
@UseGuards(JwtAuthGuard, RolesGuard)
export class UserController {
constructor(
private readonly userService: UserService
) { }

@Get()
@ApiOperation({ summary: '查询用户列表' })
@Permissions('sys:user:list')
async list(@Query() dto: QueryUserDto): Promise<Result> {
console.log(dto)
const res = await this.userService.page(dto)
return Result.ok(res)
// throw new ForbiddenException()
}
}

通过RolesGuard进行角色权限校验
roles.guard.ts

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
import { Injectable, CanActivate, ExecutionContext, ForbiddenException } from '@nestjs/common';
import { Reflector } from '@nestjs/core';
import { Observable } from 'rxjs';

@Injectable()
export class RolesGuard implements CanActivate {
constructor(private reflector: Reflector) { }
async canActivate(
context: ExecutionContext,
): Promise<boolean> {
const request = context.switchToHttp().getRequest();
const user = request.user;
console.log('当前用户', user)
// 当前请求所需权限
const currentPerm = this.reflector.get<string>('permissions', context.getHandler());
console.log('当前所需权限:', currentPerm)
// 标识不需要权限
if (!currentPerm) {
return true;
}
// 根据用户id 查询所拥有的权限
// const permList = await this.permSerivce.findUserPerms(user.id)
// const perms: string[] = []
// for (let i = 0, len = permList.length; i < len; i++) {
// permList[i]['m_perms'].indexOf(',') > -1 ? perms.push(...permList[i]['m_perms'].split(',')) : perms.push(permList[i]['m_perms'])
// }
// 匹配权限
// if (perms.includes(currentPerm)) return true
// throw new ForbiddenException()
}
}