2022-11-13 Nest.js 中关于守卫的使用
参考:
Nest.js:https://docs.nestjs.cn/
守卫:https://docs.nestjs.cn/9/guards
基本使用
在 Nest.js 中,守卫是一个使用 @Injectable()
装饰器的类,守卫应该实现 CanActivate
接口。
一个简单的例子如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| import { Injectable, CanActivate, ExecutionContext } from '@nestjs/common'; import { Observable } from 'rxjs';
@Injectable() export class AuthGuard implements CanActivate { canActivate( context: ExecutionContext, ): boolean | Promise<boolean> | Observable<boolean> { const request = context.switchToHttp().getRequest(); return validateRequest(request); } }
|
深入使用
自定义元数据
在守卫的执行过程中,难免会需要根据不同的情况做不同的处理,此时就需要用到自定义元数据。
在 Nest.js 中,自定义元数据是非常方便的,可以使用 @SetMetadata()
装饰器将定制元数据。
1 2 3 4 5 6 7
| @Post() @SetMetadata('roles', ['admin']) async create(@Body() createCatDto: CreateCatDto) { this.catsService.create(createCatDto); }
|
很显然的是,直接调用 @SetMetadata()
并不是一个很好的做法,更好的写法是创建自己的装饰器,例如:
1 2 3 4
| import { SetMetadata } from '@nestjs/common';
export const Roles = (...roles: string[]) => SetMetadata('roles', roles);
|
之后只需要在要用到的地方调用即可。
1 2 3 4 5 6
| @Post() @Roles('admin') async create(@Body() createCatDto: CreateCatDto) { this.catsService.create(createCatDto); }
|
使用元数据
在自定义了元数据之后,我们还需要拿到元数据的值才能使用,在这里可以使用 @nestjs/core
中提供的 Reflector
帮助类。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| import { Injectable, CanActivate, ExecutionContext } from '@nestjs/common'; import { Reflector } from '@nestjs/core';
@Injectable() export class RolesGuard implements CanActivate { constructor(private reflector: Reflector) {}
canActivate(context: ExecutionContext): boolean { const roles = this.reflector.get<string[]>('roles', context.getHandler()); if (!roles) { return true; } const request = context.switchToHttp().getRequest(); const user = request.user; return matchRoles(roles, user.roles); } }
|
元数据扩展
更多相关内容可参考:应用上下文
在上一节中,我们通过 context.getHandler()
来获取元数据,但这里获取的元数据只能是 方法
的,无法获取到 类
的,那么要怎么获取到 类
的元数据呢?
答案是通过 context.getClass()
,即:
1
| const roles = this.reflector.get<string[]>('roles', context.getClass());
|
那么接下来问题来了,如果要先从 类
获取元数据,再从 方法
获取元数据,要怎么办呢?
Nest.js 也提供了相应的方案。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| @Roles('user') @Controller('cats') export class CatsController { @Post() @Roles('admin') async create(@Body() createCatDto: CreateCatDto) { this.catsService.create(createCatDto); } }
const roles = this.reflector.getAllAndOverride<string[]>('roles', [ context.getHandler(), context.getClass(), ]);
const roles = this.reflector.getAllAndOverride<string[]>('roles', [ context.getHandler(), context.getClass(), ]);
|
总结
通过 @SetMetadata()
设置元数据,再通过 Reflector
获取元数据,我们就可以非常方便的在守卫、拦截器、管道或者其他 Nest.js 组件中使用元数据,极大的简化了装饰器的使用。
本文作者:草梅友仁
本文地址: https://blog.cmyr.ltd/archives/b26331ff.html
版权声明:转载请注明出处!