Nestjs自定義注解實(shí)現(xiàn)接口權(quán)限控制詳解
正文
當(dāng)業(yè)務(wù)接口開(kāi)發(fā)完成之后,正式上線之前還需要對(duì)每個(gè)接口進(jìn)行權(quán)限控制。比如刪除用戶只能管理員角色操作,查詢?nèi)坑脩糁挥泄芾韱T有權(quán)限等。
對(duì)接口實(shí)現(xiàn)權(quán)限控制有很多種方案,最簡(jiǎn)單的實(shí)現(xiàn)是在每個(gè)接口的 controller 層進(jìn)行判斷,但這樣不優(yōu)雅,冗余代碼多,且對(duì)業(yè)務(wù)侵入比較強(qiáng)。合理的權(quán)限控制方案應(yīng)該是跟業(yè)務(wù)邏輯松耦合。
Nest 官方文檔為我們提供了幾種權(quán)限控制方式,我們來(lái)實(shí)現(xiàn)最基礎(chǔ)的基于角色的 RBAC(Role-based access control) 控制方案。
實(shí)現(xiàn) RBAC 權(quán)限控制一共需要五步:
- 定義角色的枚舉類 Role
- 聲明自定義注解(裝飾器)roles.decorators.ts
- 實(shí)現(xiàn)角色守衛(wèi) RolesGuard
- 在 app.module.ts 的 providers 中引入 RolesGuard
- 在需要的接口上添加注解:
@Roles(Role.Admin, Role.SuperAdmin)?
定義角色枚舉
梳理好系統(tǒng)中一共有多少種角色,并為每種角色確定好 Code,然后聲明為枚舉類型。這里的角色類型可以自定義,根據(jù)業(yè)務(wù)需要設(shè)多少都行。
export enum Role { SuperAdmin = 'SuperAdmin', Admin = 'Admin', Normal = 'Normal', Guest = 'Guest', }
聲明自定義注冊(cè)(裝飾器)
新建一個(gè) roles.decorator.ts
文件,就可以在 Controller 中使用 @Roles
注解了
import { SetMetadata } from '@nestjs/common'; import { Role } from '@constants'; export const ROLES_KEY = 'roles'; export const Roles = (...roles: Role[]) => SetMetadata(ROLES_KEY, roles);
實(shí)現(xiàn)角色守衛(wèi) RolesGuard
新建 roles.gurad.ts
文件,它的作用是告訴 nest 什么情況下請(qǐng)求應(yīng)該被攔截,什么情況下請(qǐng)求應(yīng)該被通過(guò)。
通過(guò) reflector
可以拿到注解中傳入的角色 code 列表,通過(guò) context.switchToHttp().getRequest()
可以拿到 request 對(duì)象。因?yàn)槲覀兪褂昧?jwt,在 JwtStrategy?
中往 user 對(duì)象中寫(xiě)入了當(dāng)前登錄用戶的角色信息,所以可以通過(guò)從 request 中取 user 的方式得到角色列表。這塊具體的獲取方式根據(jù)你的業(yè)務(wù)而定,業(yè)務(wù)中把角色信息放在了什么地方,就從哪里取。
拿到注解中傳入的角色,和用戶已有的角色進(jìn)行對(duì)比,如果用戶角色中包含需要的角色,則返回 true,如果返回 false,則會(huì)拋出默認(rèn)的異常如下:
{ "statusCode": 403, "message": "Forbidden resource", "error": "Forbidden" }
我們需要定制錯(cuò)誤信息,以使整個(gè)系統(tǒng)保持一致,則拋出一個(gè)自定義異常,這個(gè)異常按照統(tǒng)一規(guī)定的格式返回錯(cuò)誤信息。
import { Injectable, CanActivate, ExecutionContext } from '@nestjs/common'; import { Reflector } from '@nestjs/core'; import { ROLES_KEY } from '../decorators/roles.decorator'; import { Role } from '@constants'; import { InternalErrorException } from '../../exception/InternalErrorException'; import { errorResult } from '@utils'; import { ErrorCodes } from '@constants/errorCode'; @Injectable() export class RolesGuard implements CanActivate { constructor(private reflector: Reflector) {} canActivate(context: ExecutionContext): boolean { const requiredRoles = this.reflector.getAllAndOverride<Role[]>(ROLES_KEY, [ context.getHandler(), context.getClass(), ]); if (!requiredRoles) { return true; } const { user } = context.switchToHttp().getRequest(); const roleCodes = user.roles?.map((item) => item.code); const flag = requiredRoles.some((role) => roleCodes?.includes(role)); if (!flag) { throw new InternalErrorException(errorResult(ErrorCodes.NoAuth)); } return flag; } }
在 providers 中引入 RolesGuard
如果想在全局使用自定義注解,就在 app.module.ts
中全局引入。如果僅想在某個(gè) controller 中使用,則在這個(gè) controller 層級(jí)的 module 中聲明。
providers: [ { provide: APP_GUARD, useClass: RolesGuard, }, ],
使用注解
在接口上使用自定義注解實(shí)現(xiàn)權(quán)限校驗(yàn)。
括號(hào)里可以寫(xiě)一個(gè)權(quán)限,也可以寫(xiě)多個(gè),因?yàn)槲覀?roles.decorator.ts
中寫(xiě)的參數(shù)類型為 Role[]
@Get() @Roles(Role.Admin, Role.SuperAdmin) async findAll() { const users = await this.userService.findAll(); return successResult(users); }
至此,使用自定義注冊(cè)實(shí)現(xiàn)接口權(quán)限控制就完成啦。
以上就是Nestjs自定義注解實(shí)現(xiàn)接口權(quán)限控制詳解的詳細(xì)內(nèi)容,更多關(guān)于Nestjs注解接口權(quán)限的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
用Nodejs實(shí)現(xiàn)在終端中炒股的實(shí)現(xiàn)
這篇文章主要介紹了用Nodejs實(shí)現(xiàn)在終端中炒股的實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2020-10-10Node.js readline 逐行讀取、寫(xiě)入文件內(nèi)容的示例
本篇文章主要介紹了Node.js readline逐行讀取、寫(xiě)入文件內(nèi)容的示例,運(yùn)用readline逐行讀取的兩種實(shí)現(xiàn),小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2018-03-03Nodejs + sequelize 實(shí)現(xiàn)增刪改查操作
這篇文章主要介紹了Nodejs + sequelize 實(shí)現(xiàn)增刪改查操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2020-11-11node前端開(kāi)發(fā)模板引擎Jade的入門(mén)
這篇文章主要介紹了node前端開(kāi)發(fā)模板引擎Jade的入門(mén),小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2018-05-05Node.js同時(shí)安裝多個(gè)版本及相關(guān)配置指南(簡(jiǎn)單易操作)
在實(shí)際開(kāi)發(fā)過(guò)程中我們可能需要安裝多個(gè)版本的 nodejs,下面這篇文章主要給大家介紹了關(guān)于Node.js同時(shí)安裝多個(gè)版本及相關(guān)配置的相關(guān)資料,文中通過(guò)圖文介紹的非常詳細(xì),需要的朋友可以參考下2023-11-11剖析Node.js異步編程中的回調(diào)與代碼設(shè)計(jì)模式
這篇文章主要介紹了Node.js異步編程中的回調(diào)與代碼設(shè)計(jì)模式,雖然大多數(shù)場(chǎng)合回調(diào)編寫(xiě)時(shí)的長(zhǎng)串括號(hào)不怎么好看,但Node的異步性能確實(shí)很好,需要的朋友可以參考下2016-02-02