守卫
作用
比如说 有些接口只有管理员才能访问,普通用户没有权限访问,那么这个时候就可以使用守卫来控制权限
守卫只接受 true 或者 false,如果返回 true 则继续执行,如果返回 false 则抛出异常
基础版
创建自定义守卫
ts
import {
CanActivate,
ExecutionContext,
HttpException,
Injectable,
} from "@nestjs/common";
import { Observable } from "rxjs";
@Injectable()
export class GlobalGuard implements CanActivate {
canActivate(
context: ExecutionContext
): boolean | Promise<boolean> | Observable<boolean> {
const request = context.switchToHttp().getRequest();
// 白名单
const whiteList = ["/logins", "/logins/test"];
// 验证
if (whiteList.includes(request.url)) {
return true;
} else {
throw new HttpException("没有权限", 403);
}
}
}
全局挂载守卫
ts
import { Module } from "@nestjs/common";
import { LoginModule } from "./Login/login.module";
import { GlobalGuard } from "./Global/Gurds/global.guard";
import { GlobalExceptionFilter } from "./Global/filter/global.filter";
import { APP_FILTER, APP_GUARD } from "@nestjs/core";
@Module({
imports: [LoginModule],
controllers: [],
providers: [
{
provide: APP_GUARD,
useClass: GlobalGuard,
},
{
provide: APP_FILTER,
useClass: GlobalExceptionFilter,
},
],
})
export class AppModule {}
局部守卫
- 新建一个守卫
ts
import {
CanActivate,
ExecutionContext,
HttpException,
Injectable,
} from "@nestjs/common";
import { Observable, of } from "rxjs";
@Injectable()
export class CustomGuard implements CanActivate {
canActivate(
context: ExecutionContext
): boolean | Promise<boolean> | Observable<boolean> {
const req = context.switchToHttp().getRequest();
if (req.headers["authorization"] == "123456") {
return true;
} else {
// throw new HttpException('没权限666', 403);
return false;
}
}
}
- 在控制器中使用守卫
ts
import { CustomGuard } from '../../Global/Gurds/custom.guard';
import {
Controller,
Get,
Inject,
UseGuards,
} from '@nestjs/common';
// 使用守卫
@Get('test2')
@UseGuards(CustomGuard)
findAlltest2() {
return this.loginService.findAll();
}
警告
- 如果全局守卫和局部守卫同时存在,那么先执行全局守卫,再执行局部守卫
- 如果 return false 它也相当于抛出异常,只不过没有传递 message 它找默认的
进阶版
授权
- (1) 先通过 token 获取用户信息,然后判断用户是否具有权限,如果具有权限则添加权限,否则就不添加
ts
import { CanActivate, ExecutionContext, Injectable } from "@nestjs/common";
import { Observable } from "rxjs";
@Injectable()
export class SetGuard implements CanActivate {
canActivate(
context: ExecutionContext
): boolean | Promise<boolean> | Observable<boolean> {
const request = context.switchToHttp().getRequest();
if (request.headers["authorization"] == "123456") {
request.roles = ["admin", "user"];
}
return true;
}
}
- (2) 自定义装饰器
ts
import { SetMetadata } from "@nestjs/common";
export const Role = (args: string[]) => SetMetadata("roles", args);
注意
roles 名字可以换 对应下面的自定义装饰器 reflector 里面的名字
- (3) 把授权装饰器绑定到全局 ,路由上面有自定义装饰器,那么就会执行守卫
- 绑定到全局
ts
import { Module } from "@nestjs/common";
import { LoginModule } from "./Login/login.module";
import { SetGuard } from "./Global/Gurds/set.guard";
import { GlobalExceptionFilter } from "./Global/filter/global.filter";
import { APP_FILTER, APP_GUARD } from "@nestjs/core";
@Module({
imports: [LoginModule],
controllers: [],
providers: [
{
provide: APP_GUARD,
useClass: SetGuard,
},
{
provide: APP_FILTER,
useClass: GlobalExceptionFilter,
},
],
})
export class AppModule {}
- 路由控制器使用自定义装饰器
ts
@Get('test')
@Role(['admin', 'user'])
async findAlltest() {
return this.loginService.findAll();
}
鉴权
- 创建获取权限的守卫
ts
import {
CanActivate,
ExecutionContext,
Inject,
Injectable,
} from "@nestjs/common";
import { Observable } from "rxjs";
import { Reflector } from "@nestjs/core";
@Injectable()
export class GetGuard implements CanActivate {
@Inject()
private reflector: Reflector;
canActivate(
context: ExecutionContext
): boolean | Promise<boolean> | Observable<boolean> {
// 获取到规则器中定义的roles
const roles = this.reflector.get<string[]>("roles", context.getHandler());
if (!roles) {
return true;
} else {
let ueserRole = context.switchToHttp().getRequest().roles;
return roles.some((item) => {
return ueserRole.includes(item);
});
}
}
}
- 绑定到获取权限的路由
ts
@Get('test')
@Role(['admin', 'user'])
@UseGuards(GetGuard)
async findAlltest() {
console.log('孔明');
return this.loginService.findAll();
}