如何在Nest.js中使用自定義Guard及兼容jwt情況下無需專門每個(gè)文件配置Guard

如果你對照了官方文檔,安裝JWT認(rèn)證的話步淹,你的controller可能類似于這樣

@Controller('auth/')
export class AuthController {
  constructor(
    private readonly authService: AuthService,
    private readonly helper: Helper,
  ) {}

//  獲取token(使用local策略)
  @UseGuards(LocalAuthGuard)
  @Post('access-token')
  async login(@Request() req) {
    return this.authService.login(req.user);
  }
//  解析token獲取user信息(使用Jwt策略)
  @UseGuards(JwtAuthGuard)
  @Get('user')
  getProfile(@Request() req) {
    return this.helper.getUser();   //  文檔上是 return this.request.user 我做了個(gè)封裝
  }
}

看上去很美好脐湾,帶上用戶信息請求access-token就可以獲取到access_token犁珠,不帶上token請求user接口就會401,但是有一個(gè)問題丝蹭,要是這個(gè)項(xiàng)目有很多接口/方法慢宗,都要進(jìn)行jwt驗(yàn)證,難道要一個(gè)一個(gè)的@UseGuards(JwtStrategy)去寫嗎奔穿,那多麻煩啊镜沽,還讓代碼變得丑陋,我們?yōu)槭裁床慌渲靡粋€(gè)默認(rèn)的Guard巫橄,再需要不認(rèn)證的時(shí)候單獨(dú)指定呢淘邻?
先來看看nest.js官方提供的Guard可用作用域。

第一種:作用于方法

如何在Nest.js中使用自定義Guard及兼容jwt情況下無需專門每個(gè)文件配置Guard

第二種:作用于controller
如何在Nest.js中使用自定義Guard及兼容jwt情況下無需專門每個(gè)文件配置Guard

第三種:作用于全局
如何在Nest.js中使用自定義Guard及兼容jwt情況下無需專門每個(gè)文件配置Guard

目前Nest只提供以上三種作用于湘换,如果你項(xiàng)目較大宾舅,接口較多,使用第一種和第二種豈不是要寫非常多的@UseGuards(xxxxx)彩倚,如果使用全局的話筹我,那我的獲取Token的access-token接口也會涼掉。
我目前在進(jìn)行的項(xiàng)目有十五個(gè)模塊帆离,一個(gè)一個(gè)寫我可不愿意蔬蕊。于是我準(zhǔn)備自己實(shí)現(xiàn)一個(gè)上層Guard,來對不同的請求進(jìn)行不同的策略分配

第一步:創(chuàng)建一個(gè)自定義的上層Guard
auth.guard.ts

import { Injectable, CanActivate, ExecutionContext } from '@nestjs/common';
import { Observable } from 'rxjs';
import { Reflector } from '@nestjs/core';

@Injectable()
//  自定義Guard必須實(shí)現(xiàn)canActivate方法
export class AuthGuard implements CanActivate {
  constructor(private readonly reflector: Reflector) {}
  canActivate(context: ExecutionContext): boolean | Promise<boolean> | Observable<boolean> {
  }

}

第二步:創(chuàng)建一個(gè)不需要認(rèn)證(NoAuth)的標(biāo)識位哥谷,讓部分接口不需要進(jìn)行jwt的驗(yàn)證
我在這里選擇創(chuàng)建一個(gè)裝飾器岸夯,使用SetMetadata()方法設(shè)置一個(gè)bool值麻献,用于告訴這個(gè)RoleAuthGuard,他不需要進(jìn)行jwt的策略認(rèn)證(我將它放在common下)

如何在Nest.js中使用自定義Guard及兼容jwt情況下無需專門每個(gè)文件配置Guard
import { SetMetadata } from '@nestjs/common'

export const NoAuth = () => SetMetadata('no-auth', true);

第三步:返回完善RoleAuthGuard

import { Injectable, CanActivate, ExecutionContext } from '@nestjs/common';
import { Observable } from 'rxjs';
import { Reflector } from '@nestjs/core';
import { AuthGuard, IAuthGuard } from '@nestjs/passport';

@Injectable()
export class RoleAuthGuard implements CanActivate {
  constructor(private readonly reflector: Reflector) {}
  canActivate(context: ExecutionContext): boolean | Promise<boolean> | Observable<boolean> {
  //    在這里取metadata中的no-auth猜扮,得到的會是一個(gè)bool
    const noAuth = this.reflector.get<boolean>('no-auth', context.getHandler());
    const guard = RoleAuthGuard.getAuthGuard(noAuth);
    return guard.canActivate(context);  //  執(zhí)行所選策略Guard的canActivate方法
  }

//  根據(jù)NoAuth的t/f選擇合適的策略Guard
  private static getAuthGuard(noAuth: boolean): IAuthGuard {
    if (noAuth) {
      return new (AuthGuard('local'))();
    } else {
      return new (AuthGuard('jwt'))();
    }
  }
}

第四步:設(shè)置這個(gè)Guard為全局使用

import { APP_FILTER, APP_GUARD } from '@nestjs/core';
import { AllExceptionsFilter } from '@/all-exception.filter';
import { RoleAuthGuard } from '@/auth/guards/role-auth.guard';
@Module({
  imports: [...],
  providers: [
  //    此為過濾全局異常勉吻,可以忽略
    {
      provide: APP_FILTER,
      useClass: AllExceptionsFilter,
    },
    //  設(shè)置全局守衛(wèi),useClass為自定義的Guard
    {
      provide: APP_GUARD,
      useClass: RoleAuthGuard,
    },
    ...
  ],
})
export class AppModule {}

最后旅赢,使用Postman進(jìn)行測試齿桃,默認(rèn)會使用Jwt策略,在不需要認(rèn)證的位置加上@NoAuth()即可

如何在Nest.js中使用自定義Guard及兼容jwt情況下無需專門每個(gè)文件配置Guard
如何在Nest.js中使用自定義Guard及兼容jwt情況下無需專門每個(gè)文件配置Guard
如何在Nest.js中使用自定義Guard及兼容jwt情況下無需專門每個(gè)文件配置Guard
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末煮盼,一起剝皮案震驚了整個(gè)濱河市短纵,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌僵控,老刑警劉巖香到,帶你破解...
    沈念sama閱讀 211,743評論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異喉祭,居然都是意外死亡养渴,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,296評論 3 385
  • 文/潘曉璐 我一進(jìn)店門泛烙,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人翘紊,你說我怎么就攤上這事蔽氨。” “怎么了帆疟?”我有些...
    開封第一講書人閱讀 157,285評論 0 348
  • 文/不壞的土叔 我叫張陵鹉究,是天一觀的道長。 經(jīng)常有香客問我踪宠,道長自赔,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,485評論 1 283
  • 正文 為了忘掉前任柳琢,我火速辦了婚禮绍妨,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘柬脸。我一直安慰自己他去,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,581評論 6 386
  • 文/花漫 我一把揭開白布倒堕。 她就那樣靜靜地躺著灾测,像睡著了一般。 火紅的嫁衣襯著肌膚如雪垦巴。 梳的紋絲不亂的頭發(fā)上媳搪,一...
    開封第一講書人閱讀 49,821評論 1 290
  • 那天铭段,我揣著相機(jī)與錄音,去河邊找鬼秦爆。 笑死稠项,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的鲜结。 我是一名探鬼主播展运,決...
    沈念sama閱讀 38,960評論 3 408
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼精刷!你這毒婦竟也來了拗胜?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,719評論 0 266
  • 序言:老撾萬榮一對情侶失蹤怒允,失蹤者是張志新(化名)和其女友劉穎埂软,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體纫事,經(jīng)...
    沈念sama閱讀 44,186評論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡勘畔,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,516評論 2 327
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了丽惶。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片炫七。...
    茶點(diǎn)故事閱讀 38,650評論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖钾唬,靈堂內(nèi)的尸體忽然破棺而出万哪,到底是詐尸還是另有隱情,我是刑警寧澤抡秆,帶...
    沈念sama閱讀 34,329評論 4 330
  • 正文 年R本政府宣布奕巍,位于F島的核電站,受9級特大地震影響儒士,放射性物質(zhì)發(fā)生泄漏的止。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,936評論 3 313
  • 文/蒙蒙 一着撩、第九天 我趴在偏房一處隱蔽的房頂上張望诅福。 院中可真熱鬧,春花似錦睹酌、人聲如沸权谁。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,757評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽旺芽。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間采章,已是汗流浹背运嗜。 一陣腳步聲響...
    開封第一講書人閱讀 31,991評論 1 266
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留悯舟,地道東北人担租。 一個(gè)月前我還...
    沈念sama閱讀 46,370評論 2 360
  • 正文 我出身青樓,卻偏偏與公主長得像抵怎,于是被迫代替她去往敵國和親奋救。 傳聞我的和親對象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,527評論 2 349