概述
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() } }
|