Nestjs框架: 接口安全與響應脫敏實踐 --- 從攔截器到自定義序列化裝飾器

接口安全問題:敏感數據脫敏的必要性


在用戶注冊成功后,若直接將用戶數據(如密碼、ID 等)返回給前端,存在嚴重的安全風險
為此,需要在接口響應前對數據進行脫敏處理

關鍵點:

  • 敏感字段(如 password)必須脫敏
  • 避免在響應中暴露數據庫字段
  • 統一脫敏邏輯,避免手動 delete 的繁瑣與錯誤

使用 NestJS 攔截器實現脫敏


NestJS 提供了強大的攔截器機制,可在請求處理前后插入邏輯,特別適用于響應數據的統一處理

攔截器的核心作用

  • 攔截器(Interceptor) 是 NestJS 提供的 AOP(面向切面編程)工具之一
  • 用于在請求處理前后插入邏輯

應用場景:

  • 響應數據脫敏
  • 日志記錄
  • 性能監控
  • 數據轉換

攔截器的生命周期:

  • 在 控制器(Controller)之后、響應返回前 執行
  • 可以對返回數據進行修改或包裝

攔截器的優勢:

  • 可以在響應階段攔截數據流
  • 支持全局攔截器、控制器攔截器和路由攔截器
  • 可以組合多個攔截邏輯,如日志記錄 + 數據脫敏

攔截器的執行流程:

  • 進入攔截器(intercept 方法)
  • 調用 next.handle() 啟動后續流程
  • 使用 pipemap 攔截響應數據
  • 返回處理后的響應數據

核心代碼示例

import { Observable, of } from 'rxjs';
import { map } from 'rxjs/operators';@Injectable()
export class TransformResponseInterceptor implements NestInterceptor {intercept(context: ExecutionContext, next: CallHandler): Observable<any> {return next.handle().pipe( map(data => {delete data.password; return data;}));}
}

使用方式

@UseInterceptors(TransformResponseInterceptor)
@Controller('auth')
export class AuthController { ... }

高級脫敏:內置攔截器 ClassSerializerInterceptor 的使用


1 )引入 class-transformer 和 class-validator

$ npm install class-transformer class-validator

2 )使用 @Exclude() 裝飾器定義脫敏字段

import { Exclude } from 'class-transformer';export class PublicUserDto {id: number;username: string;@Exclude()password: string;
}

3 )使用 ClassSerializerInterceptor

@UseInterceptors(new ClassSerializerInterceptor(PublicUserDto))

核心優勢:

  • 基于 DTO 的響應模型,結構清晰

  • 字段可見性控制(expose/exclude)

  • 支持繼承與復用

  • 字段脫敏邏輯集中管理

  • 可以全局應用

  • 使用內置 ClassSerializerInterceptor 實現序列化脫敏

  • NestJS 內置了 ClassSerializerInterceptor,結合 @Exclude()@Expose() 裝飾器可實現更細粒度的數據脫敏

使用方式:

@UseInterceptors(new ClassSerializerInterceptor())
@Post('signup')
async signup(): Promise<PublicUserDto> {const user = await this.userService.create();return new PublicUserDto(user);
}

自定義攔截器與裝飾器:提升脫敏靈活性與復用性


為避免重復 new PublicUserDto(user) 的寫法,可以封裝自定義裝飾器與攔截器,實現更簡潔的 API 響應定義

自定義裝飾器:@Serialize(PublicUserDto)

import { UseInterceptors } from '@nestjs/common';
import { SerializeInterceptor } from './serialize.interceptor';export function Serialize(dto: any) {return UseInterceptors(new SerializeInterceptor(dto));
}

自定義攔截器:自動轉換響應對象

import { plainToInstance } from 'class-transformer';@Injectable()
export class SerializeInterceptor implements NestInterceptor {constructor(private readonly dto: any) {}intercept(context: ExecutionContext, next: any): Observable<any> {return next.handle().pipe(map(data => {return plainToInstance(this.dto, data, {excludeExtraneousValues: true,});}),);}
}

控制器使用方式:

@Post('signup')
@Serialize(PublicUserDto)
async signup(): Promise<User> {return await this.userService.create();
}

優勢:

接口返回無需手動 new DTO。
支持字段控制(@Expose() / @Exclude())。
可靈活配置是否啟用類型轉換。

高階特性:靈活配置與類型轉換

通過配置 enableImplicitConversionexcludeExtraneousValues,可以實現字段的自動類型轉換與嚴格過濾。

配置項說明:

配置項作用推薦值
excludeExtraneousValues控制是否排除未標記字段true
enableImplicitConversion啟用隱式類型轉換(如 number → string)true

示例:自動轉換時間字符串為 Date

class PublicUserDto {id: number;username: string;@Type(() => Date)@Expose()createdAt: Date;
}

總結與建議


1 ) 安全性是接口設計的核心

  • 敏感字段必須脫敏
  • 脫敏邏輯應統一、可復用
  • 使用 DTO + 攔截器是最佳實踐

2 ) NestJS 提供了豐富的攔截機制

  • 攔截器可作用于全局、控制器、路由三個層級
  • 支持響應數據的統一處理、轉換與過濾

3 ) 類型轉換庫(class-transformer)增強脫敏能力

  • 支持字段暴露/隱藏
  • 支持自動類型轉換
  • 支持繼承與組合復用

4 ) 自定義裝飾器提升開發效率

  • 封裝攔截器邏輯
  • 簡化控制器代碼
  • 提高可維護性與一致性

擴展建議

  • 全局攔截器設置:可將 ClassSerializerInterceptor 或自定義攔截器注冊為全局中間件
  • 異常攔截器:統一處理錯誤信息,避免暴露內部錯誤
  • 日志攔截器:記錄請求耗時、參數與響應數據,用于性能監控
  • 多層脫敏機制:結合管道校驗 + 攔截器脫敏 + 日志脫敏,構建全方位安全體系

完整代碼示例


1 ) DTO 定義

import { Exclude, Expose, Type } from 'class-transformer';export class PublicUserDto {@Expose()id: number;@Expose()username: string;@Exclude()password: string;@Expose()@Type(() => Date)createdAt: Date;
}

2 ) 自定義攔截器

import { Injectable, NestInterceptor, ExecutionContext, Observable } from '@nestjs/common';
import { map } from 'rxjs';
import { plainToInstance } from 'class-transformer';@Injectable()
export class SerializeInterceptor implements NestInterceptor {constructor(private dto: any) {}intercept(context: ExecutionContext, next: any): Observable<any> {return next.handle().pipe(map(data => {return plainToInstance(this.dto, data, {excludeExtraneousValues: true,enableImplicitConversion: true,});}),);}
}

3 ) 自定義裝飾器

import { UseInterceptors } from '@nestjs/common';
import { SerializeInterceptor } from './serialize.interceptor';export function Serialize(dto: any) {return UseInterceptors(new SerializeInterceptor(dto));
}

4 ) 控制器使用

@Serialize(PublicUserDto)
@Post('signup')
async signUp(@Body() userDto: UserDto) {const user = await this.authService.signUp(userDto); return user;
}

優勢:

接口返回無需手動 new DTO
支持字段控制(@Expose() / @Exclude())
可靈活配置是否啟用類型轉換

攔截器的執行順序與層級說明

NestJS 中攔截器支持 全局、控制器、路由 三個層級的注冊,執行順序如下:

全局攔截器
控制器攔截器
路由攔截器
驗證方式:

intercept(context: ExecutionContext, next: CallHandler): Observable<any> {console.log('Before...');  // 攔截器前置邏輯return next.handle().pipe( tap(() => console.log('After...'))  // 攔截器后置邏輯);
}

執行順序:

  • 前置邏輯按層級順序執行。
  • 后置邏輯按反序執行(先進后出)

關鍵知識點總結與技術對比

技術點功能應用階段使用場景優勢劣勢
delete 字段刪除敏感字段控制器內字段少時簡單易用易出錯、不易維護
攔截器統一處理響應數據響應前數據脫敏、日志記錄可復用、集中管理需掌握 RxJS
ClassSerializerInterceptor內置序列化攔截器響應前DTO 轉換、字段過濾支持裝飾器、繼承配置較固定
自定義攔截器 + 裝飾器自定義序列化邏輯響應前靈活數據處理可擴展、可配置需封裝、學習曲線高

攔截器(Interceptor)與守衛(Guard)的區別與協作

區別

特性攔截器守衛
作用階段請求后/響應前(控制器方法執行前后)請求前(路由訪問控制)
核心職責數據轉換、日志、緩存、響應格式化權限驗證(角色/RBAC)、訪問控制
依賴上下文ExecutionContext(執行上下文)ExecutionContext + Reflector
返回值影響可修改響應數據決定請求是否繼續(無權則拋異常)

協作示例:身份驗證 + 響應脫敏

// 1. 守衛:JWT 權限校驗 
@Injectable()
export class AuthGuard implements CanActivate {canActivate(context: ExecutionContext): boolean {const request = context.switchToHttp().getRequest();const token = request.headers.authorization?.split(' ')[1];return verifyToken(token); // 驗證邏輯}
}// 2. 攔截器:敏感數據脫敏
@Injectable()
export class DataSanitizeInterceptor implements NestInterceptor {intercept(context: ExecutionContext, next: CallHandler): Observable<any> {return next.handle().pipe(map(data => {delete data.password; // 刪除密碼字段return data;}));}
}// 3. 控制器:協作使用 
@UseGuards(AuthGuard)
@UseInterceptors(DataSanitizeInterceptor)
@Controller('users')
export class UserController {@Get('profile')getProfile() { ... }
}

協作場景

  1. 順序:守衛 → 控制器 → 攔截器
  2. 典型流程:
    • 守衛驗證用戶權限(如角色校驗)
    • 攔截器處理響應數據(如脫敏敏感字段)

關鍵點:守衛控制 能否訪問,攔截器控制 如何響應[[1]6]。

響應攔截器與請求管道的結合使用

協作架構

graph LR A[請求] --> B[請求管道:數據校驗]B --> C[控制器業務邏輯]C --> D[響應攔截器:數據轉換]

代碼示例:驗證 + 日志

// 1. 管道:DTO 驗證(使用 class-validator)
@Injectable()
export class ValidationPipe implements PipeTransform {transform(value: any, metadata: ArgumentMetadata) {const schema = plainToClass(metadata.metatype, value);const errors = validateSync(schema);if (errors.length > 0) throw new BadRequestException(errors);return value;}
}// 2. 攔截器:統一日志記錄
@Injectable()
export class LoggingInterceptor implements NestInterceptor {intercept(context: ExecutionContext, next: CallHandler): Observable<any> {const request = context.switchToHttp().getRequest();console.log(`[Request] ${request.method} ${request.url}`);return next.handle().pipe(tap(() => console.log(`[Response] Status: ${context.getResponse().statusCode}`)));}
}// 3. 控制器應用 
@UsePipes(ValidationPipe)
@UseInterceptors(LoggingInterceptor)
@Post('register')
register(@Body() userDto: UserDto) { ... }

應用場景

  • 請求階段:管道校驗參數合法性(如郵箱格式)
  • 響應階段:攔截器記錄請求耗時、錯誤日志[[1]3]

基于攔截器實現接口緩存與響應壓縮


1 ) 接口緩存攔截器

import { CACHE_MANAGER, Inject, Injectable } from '@nestjs/common';@Injectable()
export class CacheInterceptor implements NestInterceptor {constructor(@Inject(CACHE_MANAGER) private cacheManager: Cache) {}async intercept(context: ExecutionContext, next: CallHandler) {const request = context.switchToHttp().getRequest();const key = request.originalUrl;const cached = await this.cacheManager.get(key);if (cached) return of(cached); // 返回緩存return next.handle().pipe(tap(data => this.cacheManager.set(key, data, { ttl: 60 })) // 緩存60秒 );}
}

2 ) 響應壓縮攔截器(使用 compression 庫)

import * as compression from 'compression';@Injectable()
export class CompressionInterceptor implements NestInterceptor {intercept(context: ExecutionContext, next: CallHandler) {const response = context.switchToHttp().getResponse();compression({ level: 6 })(request, response, () => next.handle()); // 壓縮級別1-9}
}

應用場景:

  • 緩存:高頻查詢接口(如商品列表)
  • 壓縮:大文本響應(如報告導出)

注意:壓縮攔截器需在全局注冊,避免多次壓縮

自定義響應格式(統一返回結構)


方案:全局攔截器封裝

// 1. 定義統一響應DTO 
export class SuccessResponseDto<T> {code: number;data: T;message: string;constructor(data: T, message = 'Success', code = 200) {this.code = code;this.data = data;this.message = message;}
}// 2. 全局響應攔截器
@Injectable()
export class ResponseFormatInterceptor implements NestInterceptor {intercept(context: ExecutionContext, next: CallHandler): Observable<any> {return next.handle().pipe(map(rawData => new SuccessResponseDto(rawData)), // 包裝成功響應 catchError(err => throwError(() => { // 錯誤處理return new ErrorResponseDto(err.message, err.status);})));}
}// 3. 在 main.ts 全局注冊 
app.useGlobalInterceptors(new ResponseFormatInterceptor());

響應效果:

{"code": 200,"data": { "id": 1, "name": "John" },"message": "Success"
}

優勢:

  • 統一成功/錯誤響應格式
  • 隱藏技術細節(如數據庫錯誤堆棧)
  • 標準化前端對接

最佳實踐總結

  1. 分層職責:
    • 守衛 → 訪問控制
    • 管道 → 數據校驗
    • 攔截器 → 數據轉換/增強
  2. 性能優化:
    • 緩存攔截器減少 DB 查詢
    • 壓縮攔截器降低網絡開銷
  3. 維護性:
    • 統一響應格式提升前后端協作效率

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/pingmian/92300.shtml
繁體地址,請注明出處:http://hk.pswp.cn/pingmian/92300.shtml
英文地址,請注明出處:http://en.pswp.cn/pingmian/92300.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

Python包與虛擬環境工具全景對比:從virtualenv到uv的演進

Python 的開發環境管理一直是綜合性的工程問題。隨著工具和規范的不斷進化&#xff0c;我們看到了從 virtualenv / pip 開始&#xff0c;到 pipenv 和 poetry 的環境一體化&#xff0c;再到 uv 和 hatch 這樣的一體化、高性能新生代工具。 本文將對比這些工具的特點、優勢和選型…

期貨和期權對沖后能盈利嗎?

本文主要介紹期貨和期權對沖后能盈利嗎&#xff1f;期貨和期權作為金融衍生品的兩大核心工具&#xff0c;其組合對沖策略的盈利性取決于市場走勢、策略設計、成本管控及風險對沖效果。對沖的本質是降低風險&#xff0c;但通過合理設計&#xff0c;部分策略可在對沖風險的同時創…

【其他分類】Showrunner AI版的Netflix 互動故事創作平臺 進行動畫生成與微調、角色場景創建

Showrunner是一個AI 驅動的角色場景動畫。視覺風格較為統一&#xff0c;偏向 3D Q 版卡通風格&#xff0c;支持語音對白修改、鏡頭相機切換、動畫角色和場景設置等功能。 論文原文中文翻譯官方地址pdf版 、網頁版pdf版https://www.showrunner.xyz/ 當前的2D 動畫軟件&#xff…

K8s 常見故障案例分析

#作者&#xff1a;程宏斌 文章目錄一、節點故障&#xff08;一&#xff09;節點 NotReady 狀態排查步驟解決方案二、Pod 故障&#xff08;一&#xff09;Pod 一直處于 Pending 狀態排查步驟解決方案&#xff08;二&#xff09;Pod 頻繁重啟故障現象排查步驟解決方案三、控制器故…

半精度權重 及 Phi-3線性層的權重分布

半精度權重 我們可以使用張量的 to() 方法以及適當的類型 torch.float16,將權重轉換為 FP16: torch.manual_seed(11) weights = torch.randn(1000) * .07 weights.min(),

Linux怎么安裝Docker?環境怎么搭建?步驟是什么?如何配置?有哪些注意事項?出現問題怎么排除?

一、Docker簡介與環境準備 1.1 什么是Docker Docker是一個開源的容器化平臺&#xff0c;它使用Linux內核的cgroup&#xff0c;namespace以及OverlayFS類的UnionFS等技術&#xff0c;對進程進行封裝隔離&#xff0c;屬于操作系統層面的虛擬化技術。Docker能夠自動執行重復性任務…

apiSQL網關調優:釋放單節點的最大潛能

前言 在構建高性能、高可用的API服務時&#xff0c;apiSQL 提供了強大的集群部署模式&#xff0c;通過橫向擴展來分散負載、提高吞吐量。然而&#xff0c;在某些場景下&#xff0c;我們同樣需要關注并最大化單個節點的處理能力。當單個 apiSQL 網關節點需要處理高并發請求或承載…

【開源工具】網絡交換機批量配置生成工具開發全解:從原理到實戰(附完整Python源碼)

?? 【開源工具】網絡交換機批量配置生成工具開發全解:從原理到實戰(附完整Python源碼) ?? 個人主頁:創客白澤 - CSDN博客 ?? 系列專欄:??《Python開源項目實戰》 ?? 熱愛不止于代碼,熱情源自每一個靈感閃現的夜晚。愿以開源之火,點亮前行之路。 ?? 希望大家…

【插件式微服務架構系統分享】之 解耦至上:gateway 網關與APISIX 網關的不同分工

【插件式微服務架構系統分享】之解耦至上&#xff1a;gateway 網關與APISIX 網關的不同分工作者&#xff1a;朱元祿一、一個比方 APISIX 就像是一個專業的高速公路收費站&#xff0c;不屬于你公司自己造的路&#xff0c;而是專門為所有車輛&#xff08;流量&#xff09;設計的&…

【感知機】感知機(perceptron)學習算法例題及詳解

感知機( perceptron )是二類分類的線性分類模型&#xff0c;其輸入為實例的特征向量&#xff0c;輸出為實例的類別&#xff0c;取1 和-1二值。感知機對應輸入空間(特征空間)中將實例劃分為正負兩類的分離超平面&#xff0c;是一種判別模型。感知機是神經網絡與支持向量機的基礎…

Linux基礎命令速查:從入門到精通

Linux常用命令指南一、操作系統概述1 . 什么是操作系統&#xff1f;2. 為什么需要操作系統&#xff1f;二、Linux基礎命令1. 目錄與文件操作2. 文件操作命令3. 文件查看命令4. 文本處理命令三、重定向1. 重定向符號四、Linux系統概念1. 文件系統特點2. 路徑規則3. 通配符五、壓…

一周學會Matplotlib3 Python 數據可視化-坐標軸 (Axis)

鋒哥原創的Matplotlib3 Python數據可視化視頻教程&#xff1a; 2026版 Matplotlib3 Python 數據可視化 視頻教程(無廢話版) 玩命更新中~_嗶哩嗶哩_bilibili 課程介紹 本課程講解利用python進行數據可視化 科研繪圖-Matplotlib&#xff0c;學習Matplotlib圖形參數基本設置&…

防火墻安全作用及 firewalld 交互、端口配置

1. 防火墻在 Linux 系統安全中有哪些重要的作用&#xff1f;網絡訪問控制&#xff1b;隔離網絡區域&#xff1b;抵御網絡攻擊&#xff1b;限制服務暴露&#xff1b;日志審計與溯源&#xff1b;隱藏內部網絡結構。2. 簡單說明一下firewalld。Firewalld服務是一種動態防火網管理器…

RabbitMQ削峰填谷詳解:讓系統在流量洪峰中“穩如泰山”

想象一下&#xff1a;雙十一零點&#xff0c;千萬用戶同時點擊下單按鈕&#xff0c;服務器該如何應對&#xff1f;這就是削峰填谷要解決的難題。而RabbitMQ正是這場戰役中的超級緩沖器&#xff01;一、什么是“峰”和“谷”&#xff1f; 峰&#xff1a;系統瞬時高并發&#xff…

數據庫表字段命名建議和最佳實踐

在設計數據庫時&#xff0c;字段命名是至關重要的&#xff0c;它直接影響到數據庫的可讀性、可維護性和團隊協作效率。以下是數據庫字段命名的一些建議和最佳實踐&#xff1a;1. 使用清晰且描述性的名稱目的&#xff1a;確保字段名能夠清晰地表達其含義&#xff0c;便于其他開發…

散點圖矩陣

create_scatterplotmatrix對角線是直方圖&#xff0c;但是框選無交互import plotly.figure_factory as fffig ff.create_scatterplotmatrix(df, diaghistogram, # 將對角線設置為直方圖)fig.update_layout(autosizeTrue, # 讓 Plotly 自動適應容器widthNone, # 設置寬度hei…

Linux驅動25 --- RkMedia音頻API使用增加 USB 音視頻設備

目錄 一、RV1126 增加 USB 音視頻設備 二、RkMedia 音頻 API 2.1 PCM 音頻輸入 系統初始化 AI 通道配置 AI 通道使能 開啟數據流 獲取數據 保存數據 2.2 編碼音頻編碼輸入 2.3 PCM 音頻輸出 一、RV1126 增加 USB 音視頻設備 配置過程 第一步&#xff1a;來到 SDK 內核路…

CETOL 6σ 幫助提升活檢器械精度并降低制造成本

某全球醫療器械企業采用 Sigmetrix 的 CETOL 6σ 公差分析軟件&#xff0c;針對一次性活檢采集器械&#xff08;Biopsy Harvesting Instrument&#xff09;完成結構優化&#xff0c;成功解決頜骨動力學缺陷、4mm孔徑精度控制及線纜傳動敏感度等核心挑戰&#xff0c;大大提高了活…

基于協同過濾算法的圖書推薦系統設計與實現/基于python的圖書推薦系統設計與實現/基于python的圖書借閱系統設計與實現

基于協同過濾算法的圖書推薦系統設計與實現采用django、vue技術用戶&#xff1a;注冊、登錄、圖書信息、公告信息、個人中心、借閱記錄、歸還記錄、我的收藏。管理員&#xff1a;登錄、用戶、圖書分類、圖書信息、借閱記錄、歸還記錄、系統管理、用戶信息。

線程組和線程池的基本用法

1.線程組1.1創建線程組的方法public class xianchengzu {public static void main(String[] args) {ThreadGroup group new ThreadGroup("group");// 創建線程組時指定父線程組ThreadGroup parent new ThreadGroup("parent");ThreadGroup child new Thr…