JSPM

  • ESM via JSPM
  • ES Module Entrypoint
  • Export Map
  • Keywords
  • License
  • Repository URL
  • TypeScript Types
  • README
  • Created
  • Published
  • Downloads 1128
  • Score
    100M100P100Q90947F
  • License ISC

A powerful NestJS boot core library with authentication, caching, validation, and logging utilities

Package Exports

  • @maxtan/nest-core
  • @maxtan/nest-core/decorators/auth.decorator.d.ts
  • @maxtan/nest-core/decorators/auth.decorator.d.ts.map
  • @maxtan/nest-core/decorators/auth.decorator.js
  • @maxtan/nest-core/decorators/auth.decorator.js.map
  • @maxtan/nest-core/decorators/index.d.ts
  • @maxtan/nest-core/decorators/index.d.ts.map
  • @maxtan/nest-core/decorators/index.js
  • @maxtan/nest-core/decorators/index.js.map
  • @maxtan/nest-core/decorators/operation-log.decorator.d.ts
  • @maxtan/nest-core/decorators/operation-log.decorator.d.ts.map
  • @maxtan/nest-core/decorators/operation-log.decorator.js
  • @maxtan/nest-core/decorators/operation-log.decorator.js.map
  • @maxtan/nest-core/decorators/xml.decorator.d.ts
  • @maxtan/nest-core/decorators/xml.decorator.d.ts.map
  • @maxtan/nest-core/decorators/xml.decorator.js
  • @maxtan/nest-core/decorators/xml.decorator.js.map
  • @maxtan/nest-core/filters/exceptions.filter.d.ts
  • @maxtan/nest-core/filters/exceptions.filter.d.ts.map
  • @maxtan/nest-core/filters/exceptions.filter.js
  • @maxtan/nest-core/filters/exceptions.filter.js.map
  • @maxtan/nest-core/filters/index.d.ts
  • @maxtan/nest-core/filters/index.d.ts.map
  • @maxtan/nest-core/filters/index.js
  • @maxtan/nest-core/filters/index.js.map
  • @maxtan/nest-core/index.d.ts
  • @maxtan/nest-core/index.d.ts.map
  • @maxtan/nest-core/index.js
  • @maxtan/nest-core/index.js.map
  • @maxtan/nest-core/interceptors/index.d.ts
  • @maxtan/nest-core/interceptors/index.d.ts.map
  • @maxtan/nest-core/interceptors/index.js
  • @maxtan/nest-core/interceptors/index.js.map
  • @maxtan/nest-core/interceptors/operation-log.interceptor.d.ts
  • @maxtan/nest-core/interceptors/operation-log.interceptor.d.ts.map
  • @maxtan/nest-core/interceptors/operation-log.interceptor.js
  • @maxtan/nest-core/interceptors/operation-log.interceptor.js.map
  • @maxtan/nest-core/modules/auth/auth.guard.d.ts
  • @maxtan/nest-core/modules/auth/auth.guard.d.ts.map
  • @maxtan/nest-core/modules/auth/auth.guard.js
  • @maxtan/nest-core/modules/auth/auth.guard.js.map
  • @maxtan/nest-core/modules/auth/auth.module.d.ts
  • @maxtan/nest-core/modules/auth/auth.module.d.ts.map
  • @maxtan/nest-core/modules/auth/auth.module.js
  • @maxtan/nest-core/modules/auth/auth.module.js.map
  • @maxtan/nest-core/modules/auth/auth.strategy.d.ts
  • @maxtan/nest-core/modules/auth/auth.strategy.d.ts.map
  • @maxtan/nest-core/modules/auth/auth.strategy.js
  • @maxtan/nest-core/modules/auth/auth.strategy.js.map
  • @maxtan/nest-core/modules/cache/cache.module.d.ts
  • @maxtan/nest-core/modules/cache/cache.module.d.ts.map
  • @maxtan/nest-core/modules/cache/cache.module.js
  • @maxtan/nest-core/modules/cache/cache.module.js.map
  • @maxtan/nest-core/modules/cache/cache.service.d.ts
  • @maxtan/nest-core/modules/cache/cache.service.d.ts.map
  • @maxtan/nest-core/modules/cache/cache.service.js
  • @maxtan/nest-core/modules/cache/cache.service.js.map
  • @maxtan/nest-core/modules/common/common.module.d.ts
  • @maxtan/nest-core/modules/common/common.module.d.ts.map
  • @maxtan/nest-core/modules/common/common.module.js
  • @maxtan/nest-core/modules/common/common.module.js.map
  • @maxtan/nest-core/modules/common/common.service.d.ts
  • @maxtan/nest-core/modules/common/common.service.d.ts.map
  • @maxtan/nest-core/modules/common/common.service.js
  • @maxtan/nest-core/modules/common/common.service.js.map
  • @maxtan/nest-core/modules/index.d.ts
  • @maxtan/nest-core/modules/index.d.ts.map
  • @maxtan/nest-core/modules/index.js
  • @maxtan/nest-core/modules/index.js.map
  • @maxtan/nest-core/modules/operation-log/operation-log.interceptor.d.ts
  • @maxtan/nest-core/modules/operation-log/operation-log.interceptor.d.ts.map
  • @maxtan/nest-core/modules/operation-log/operation-log.interceptor.js
  • @maxtan/nest-core/modules/operation-log/operation-log.interceptor.js.map
  • @maxtan/nest-core/modules/operation/index.d.ts
  • @maxtan/nest-core/modules/operation/index.d.ts.map
  • @maxtan/nest-core/modules/operation/index.js
  • @maxtan/nest-core/modules/operation/index.js.map
  • @maxtan/nest-core/modules/operation/operation.decorator.d.ts
  • @maxtan/nest-core/modules/operation/operation.decorator.d.ts.map
  • @maxtan/nest-core/modules/operation/operation.decorator.js
  • @maxtan/nest-core/modules/operation/operation.decorator.js.map
  • @maxtan/nest-core/modules/operation/operation.interceptor.d.ts
  • @maxtan/nest-core/modules/operation/operation.interceptor.d.ts.map
  • @maxtan/nest-core/modules/operation/operation.interceptor.js
  • @maxtan/nest-core/modules/operation/operation.interceptor.js.map
  • @maxtan/nest-core/modules/operation/operation.module.d.ts
  • @maxtan/nest-core/modules/operation/operation.module.d.ts.map
  • @maxtan/nest-core/modules/operation/operation.module.js
  • @maxtan/nest-core/modules/operation/operation.module.js.map
  • @maxtan/nest-core/pipes/index.d.ts
  • @maxtan/nest-core/pipes/index.d.ts.map
  • @maxtan/nest-core/pipes/index.js
  • @maxtan/nest-core/pipes/index.js.map
  • @maxtan/nest-core/pipes/validation.pipe.d.ts
  • @maxtan/nest-core/pipes/validation.pipe.d.ts.map
  • @maxtan/nest-core/pipes/validation.pipe.js
  • @maxtan/nest-core/pipes/validation.pipe.js.map
  • @maxtan/nest-core/tsconfig.tsbuildinfo
  • @maxtan/nest-core/types/auth.d.ts
  • @maxtan/nest-core/types/auth.d.ts.map
  • @maxtan/nest-core/types/auth.js
  • @maxtan/nest-core/types/auth.js.map
  • @maxtan/nest-core/types/boot.d.ts
  • @maxtan/nest-core/types/boot.d.ts.map
  • @maxtan/nest-core/types/boot.js
  • @maxtan/nest-core/types/boot.js.map
  • @maxtan/nest-core/types/index.d.ts
  • @maxtan/nest-core/types/index.d.ts.map
  • @maxtan/nest-core/types/index.js
  • @maxtan/nest-core/types/index.js.map
  • @maxtan/nest-core/types/logger.d.ts
  • @maxtan/nest-core/types/logger.d.ts.map
  • @maxtan/nest-core/types/logger.js
  • @maxtan/nest-core/types/logger.js.map
  • @maxtan/nest-core/types/operation-log.d.ts
  • @maxtan/nest-core/types/operation-log.d.ts.map
  • @maxtan/nest-core/types/operation-log.js
  • @maxtan/nest-core/types/operation-log.js.map
  • @maxtan/nest-core/utils/common.d.ts
  • @maxtan/nest-core/utils/common.d.ts.map
  • @maxtan/nest-core/utils/common.js
  • @maxtan/nest-core/utils/common.js.map
  • @maxtan/nest-core/utils/dto.d.ts
  • @maxtan/nest-core/utils/dto.d.ts.map
  • @maxtan/nest-core/utils/dto.js
  • @maxtan/nest-core/utils/dto.js.map
  • @maxtan/nest-core/utils/entries.d.ts
  • @maxtan/nest-core/utils/entries.d.ts.map
  • @maxtan/nest-core/utils/entries.js
  • @maxtan/nest-core/utils/entries.js.map
  • @maxtan/nest-core/utils/index.d.ts
  • @maxtan/nest-core/utils/index.d.ts.map
  • @maxtan/nest-core/utils/index.js
  • @maxtan/nest-core/utils/index.js.map
  • @maxtan/nest-core/utils/logger.d.ts
  • @maxtan/nest-core/utils/logger.d.ts.map
  • @maxtan/nest-core/utils/logger.js
  • @maxtan/nest-core/utils/logger.js.map
  • @maxtan/nest-core/utils/snowflake.d.ts
  • @maxtan/nest-core/utils/snowflake.d.ts.map
  • @maxtan/nest-core/utils/snowflake.js
  • @maxtan/nest-core/utils/snowflake.js.map

Readme

@maxtan/nest-core

NestJS 增强工具包,提供了一系列开箱即用的模块和工具,帮助您快速构建高效、规范的 NestJS 应用。

功能特性

  • 日志系统: 基于 winston 的灵活日志系统,支持控制台、文件、阿里云 SLS 等多种输出方式
  • 操作日志: 基于装饰器的操作日志记录,自动捕获请求信息、执行结果、耗时等
  • 缓存模块: 基于 Redis 的高性能缓存解决方案,支持生命周期管理和批量操作
  • 异常过滤器: 统一的异常处理机制,自动记录异常日志和错误追踪
  • 验证管道: 增强的数据验证管道,支持嵌套验证和配置化
  • 工具函数库: 常用辅助函数集合,使用加密安全的随机数生成
  • 授权模块: 基于 JWT 的认证和授权系统,支持多种 Token 提取策略
  • 雪花算法: 基于 @sapphire/snowflake 的分布式唯一 ID 生成器
  • XML 解析: 高性能 XML 解析装饰器,支持自定义配置和错误处理
  • TypeORM 实体基类: 提供包含通用字段(创建时间、更新时间、创建者、更新者、软删除)的基础实体类

安装

npm install @maxtan/nest-core

# 或使用 pnpm
pnpm add @maxtan/nest-core

使用指南

日志模块

基础配置

import { createLogger } from '@maxtan/nest-core'

// 在应用启动时配置日志
createLogger() // 默认配置,日志输出到控制台和文件

使用日志工具

import { logger } from '@maxtan/nest-core'

// 使用默认logger记录不同级别的日志
logger.info('普通信息')
logger.debug('调试信息')
logger.warn('警告信息')
logger.error('错误信息')

// 或使用 log 方法(需要指定级别)
logger.log('info', '普通信息')
logger.log('error', '错误信息', errorObject)

自定义配置选项

import { createLogger } from '@maxtan/nest-core'

// 自定义配置
createLogger({
  useConsole: true, // 是否输出到控制台,默认 true
  maxDays: 30, // 日志文件保留天数,默认 30 天
  maxSize: '20m', // 单个日志文件最大大小,默认 20MB
  sls: {
    // 阿里云 SLS 配置(可选)
    accessKeyId: 'your-ak',
    accessKeySecret: 'your-sk',
    projectName: 'your-project',
    logStoreName: 'your-logstore',
    // 可选配置
    endpoint: 'cn-hangzhou.log.aliyuncs.com',
    topic: 'nest-boot',
    source: 'source',
    env: 'production'
  }
})

日志文件轮转机制

日志系统使用 winston-daily-rotate-file 实现自动轮转:

  1. 按大小轮转:当单个文件达到 maxSize(20MB)时,自动创建新文件

    logs/default-2024-01-01.log       // 当前文件
    logs/default-2024-01-01.1.log.gz  // 第1个文件(已压缩)
    logs/default-2024-01-01.2.log.gz  // 第2个文件(已压缩)
  2. 按日期轮转:每天午夜自动创建新文件

    logs/default-2024-01-01.log.gz
    logs/default-2024-01-02.log.gz
    logs/default-2024-01-03.log      // 当前日期
  3. 自动压缩:旧文件自动压缩为 .gz 格式,节省磁盘空间

  4. 自动清理:超过 maxDays(30天)的文件自动删除

在 NestJS 应用中使用

import { NestFactory } from '@nestjs/core'
import { createLogger, WinstonLoggerService } from '@maxtan/nest-core'
import { AppModule } from './app.module'

async function bootstrap() {
  // 配置日志系统
  createLogger({
    useConsole: true,
    maxDays: 30,
    sls: {
      // SLS 配置...
    }
  })

  const app = await NestFactory.create(AppModule, {
    logger: new WinstonLoggerService() // 使用 Winston 作为 NestJS 日志服务
  })

  await app.listen(3000)
}
bootstrap()

缓存模块

缓存模块提供了基于 Redis 的高性能缓存解决方案,内置生命周期管理,支持批量操作、对象序列化等功能。

import { CacheModule } from '@maxtan/nest-core'

@Module({
  imports: [
    CacheModule.forRoot(
      {
        url: 'redis://localhost:6379'
        // 其他 Redis 客户端选项
      },
      true // 第二个参数表示是否全局注册模块
    )
  ]
})
export class AppModule {}

在服务中使用:

import { Injectable } from '@nestjs/common'
import { CacheService } from '@maxtan/nest-core'

@Injectable()
export class YourService {
  constructor(private readonly cacheService: CacheService) {}

  async getData(key: string) {
    // 从缓存获取数据
    const cached = await this.cacheService.get(key)
    if (cached) return cached

    // 获取数据并缓存
    const data = await this.fetchData()
    await this.cacheService.set(key, JSON.stringify(data), 3600) // 缓存1小时
    return data
  }

  // 使用对象序列化
  async getObjectData(key: string) {
    // 自动 JSON 解析
    const cached = await this.cacheService.getObject<UserData>(key)
    if (cached) return cached

    const data = await this.fetchData()
    await this.cacheService.setObject(key, data, 3600) // 自动 JSON 序列化
    return data
  }

  // 批量操作
  async batchGet(keys: string[]) {
    return await this.cacheService.mget(...keys)
  }

  async batchSet(data: Record<string, any>) {
    await this.cacheService.mset(data)
  }

  // 计数器
  async incrementCounter(key: string) {
    return await this.cacheService.incr(key)
  }

  // 检查连接状态
  async checkHealth() {
    const isReady = await this.cacheService.isReady()
    return { redis: isReady ? 'healthy' : 'unhealthy' }
  }
}

操作日志模块

操作日志模块提供了全局自动记录所有控制器方法执行情况的功能,自动捕获请求信息、执行结果、耗时等。

模块注册

在应用模块中导入 OperationModule

import { Module } from '@nestjs/common'
import { OperationModule } from '@maxtan/nest-core'

@Module({
  imports: [
    // 基础使用 - 默认全局拦截所有控制器方法
    OperationModule.forRoot()
  ]
})
export class AppModule {}

自定义配置

import { Module } from '@nestjs/common'
import { OperationModule } from '@maxtan/nest-core'

@Module({
  imports: [
    OperationModule.forRoot({
      enabled: true, // 是否启用,默认 true
      excludePaths: ['/health', '/metrics'], // 排除不需要记录日志的路径
      global: true, // 是否全局注册,默认 true
      request: false, // 是否默认记录请求参数,默认 false
      response: false, // 是否默认记录响应结果,默认 false
      idField: 'id', // 用户ID字段名,默认 'id'
      nameField: 'name' // 用户名字段名,默认 'name'
    })
  ]
})
export class AppModule {}

使用 @Operation 装饰器

@Operation 装饰器是可选的,即使不使用装饰器,拦截器也会自动记录所有控制器方法的日志。装饰器主要用于:

  1. 添加操作描述
  2. 禁用特定方法的日志记录
  3. 为特定方法配置是否记录请求和响应
import { Controller, Post, Put, Get, Body, Param } from '@nestjs/common'
import { Operation } from '@maxtan/nest-core'

@Controller('users')
export class UserController {
  // 不使用装饰器 - 自动记录日志(根据全局配置)
  @Post()
  async createUser(@Body() dto: CreateUserDto) {
    return this.userService.create(dto)
  }

  // 添加描述并记录请求和响应
  @Put(':id')
  @Operation({
    description: '更新用户信息',
    request: true, // 记录请求参数
    response: true // 记录响应结果
  })
  async updateUser(@Param('id') id: string, @Body() dto: UpdateUserDto) {
    return this.userService.update(id, dto)
  }

  // 仅记录请求,不记录响应
  @Post('login')
  @Operation({
    description: '用户登录',
    request: true
  })
  async login(@Body() dto: LoginDto) {
    return this.authService.login(dto)
  }

  // 禁用日志记录(如健康检查接口)
  @Get('health')
  @Operation({ disabled: true })
  async healthCheck() {
    return { status: 'ok' }
  }
}

配置选项

OperationModuleOptions (模块配置)

选项 类型 默认值 说明
enabled boolean true 是否启用操作日志
excludePaths string[] [] 排除的路径(支持通配符),不记录日志
global boolean true 是否全局注册
request boolean false 是否默认记录请求参数
response boolean false 是否默认记录响应结果
idField string 'id' 用户ID字段名。系统会优先使用标准字段 subuserId,如果不存在则使用此字段从 JWT payload 中获取
nameField string 'name' 用户名字段名。系统会优先使用 username,如果不存在则使用此字段从 JWT payload 中获取

OperationOptions (装饰器配置)

选项 类型 默认值 说明
description string - 操作描述,添加到日志中
disabled boolean false 是否禁用此方法的日志记录
request boolean - 是否记录请求参数(优先于全局配置)
response boolean - 是否记录响应结果(优先于全局配置)

注意:装饰器中的 requestresponse 配置优先级高于模块全局配置。

用户信息提取规则

操作日志会自动从 JWT token 中提取用户信息(如果存在认证)。为了兼容不同的 JWT payload 结构,系统使用以下优先级规则:

用户 ID 提取优先级(从高到低):

  1. payload.sub - JWT 标准字段
  2. payload.userId - 常用的用户ID字段
  3. payload[idField] - 自定义字段(由 idField 配置指定,默认 'id'

用户名提取优先级(从高到低):

  1. payload.username - 常用的用户名字段
  2. payload[nameField] - 自定义字段(由 nameField 配置指定,默认 'name'

这种灵活的配置方式使得操作日志模块可以适配各种 JWT payload 结构,无需修改现有的认证逻辑。

示例

// JWT payload 示例 1:使用标准字段
{
  "sub": "user_12345",
  "username": "john_doe"
}
// 提取结果:userId = "user_12345", username = "john_doe"

// JWT payload 示例 2:使用自定义字段
{
  "id": "12345",
  "name": "John Doe"
}
// 使用默认配置,提取结果:userId = "12345", username = "John Doe"

// JWT payload 示例 3:自定义配置
{
  "uid": "12345",
  "nickname": "JohnD"
}
// 使用配置 { idField: 'uid', nameField: 'nickname' }
// 提取结果:userId = "12345", username = "JohnD"

日志输出示例

基础日志(不记录参数和结果):

{
  "operationId": "1234567890123456789",
  "path": "/users",
  "httpMethod": "POST",
  "userId": "123",
  "username": "admin",
  "status": "success",
  "statusCode": 200,
  "duration": "45ms"
}

带描述和参数的日志:

{
  "operationId": "1234567890123456789",
  "description": "更新用户信息",
  "path": "/users/123",
  "httpMethod": "PUT",
  "userId": "123",
  "username": "admin",
  "params": {
    "username": "newuser",
    "password": "***", // 自动脱敏
    "email": "user@example.com"
  },
  "status": "success",
  "statusCode": 200,
  "duration": "45ms"
}

带结果的日志:

{
  "operationId": "1234567890123456789",
  "description": "更新用户信息",
  "path": "/users/123",
  "httpMethod": "PUT",
  "result": {
    "id": "123",
    "username": "newuser",
    "email": "user@example.com"
  },
  "status": "success",
  "statusCode": 200,
  "duration": "45ms"
}

失败请求:

{
  "operationId": "1234567890123456790",
  "path": "/users/123",
  "httpMethod": "DELETE",
  "status": "failure",
  "statusCode": 500,
  "duration": "12ms",
  "error": {
    "message": "用户不存在",
    "name": "Error"
  }
}

失败请求时,异常过滤器会单独输出堆栈信息(仅 500+ 错误或需要调试的异常):

[Stack Trace] operationId: 1234567890123456790 | errorId: 9876543210

Error: 用户不存在
    at UserService.deleteUser (D:\app\user.service.ts:45:11)
    at UserController.deleteUser (D:\app\user.controller.ts:30:28)
    at @nestjs/core/router/router-execution-context.js:38:29
    ...

字段说明

字段 说明
operationId 操作唯一 ID,用于日志追踪
description 操作描述(可选)
path 请求路径(包含路径参数)
httpMethod HTTP 方法
userId 用户 ID(从 JWT token 中获取)
username 用户名(从 JWT token 中获取)
params 请求参数(可选,自动脱敏)
result 响应结果(可选)
status 操作状态(success/failure)
statusCode HTTP 状态码
duration 执行耗时
error 错误信息(失败时,不含 stack)

错误日志关联

当操作失败时,会输出两条日志:

  1. 操作日志:包含业务上下文和错误信息(不含堆栈)
  2. 堆栈信息:由异常过滤器输出(仅 500+ 错误或需要调试的异常)

两条日志通过 operationId 关联,可以快速定位问题:

# 查看某个操作的所有相关日志
grep "1234567890" app.log

安全特性

  1. 自动脱敏 - 自动隐藏敏感字段:passwordtokensecretaccessTokenrefreshTokenapiKey
  2. 异步记录 - 异步记录日志,不影响请求性能
  3. 唯一追踪 - 每个操作生成唯一 operationId,便于日志追踪和关联
  4. 堆栈分离 - 错误堆栈与操作日志分离,通过 operationId 关联,避免日志冗余
  5. 灵活配置 - 支持全局配置和方法级配置,装饰器配置优先级更高

授权模块

授权模块提供了基于 JWT 的认证和授权功能,可以轻松集成到您的 NestJS 应用中。

基本使用

import { AuthModule } from '@maxtan/nest-core'

@Module({
  imports: [
    AuthModule.register({
      secret: 'your-jwt-secret-key'
    })
  ]
})
export class AppModule {}

自定义配置

您可以自定义 JWT 签名选项:

import { AuthModule } from '@maxtan/nest-core'

@Module({
  imports: [
    AuthModule.register({
      secret: 'your-jwt-secret-key',
      signOptions: {
        expiresIn: '7d', // Token有效期7天
        issuer: 'your-app', // 发行方
        audience: 'your-users' // 目标用户
      }
    })
  ]
})
export class AppModule {}

保护路由

使用 AuthGuard 保护您的路由:

import { Controller, Get, UseGuards } from '@nestjs/common'
import { AuthGuard } from '@maxtan/nest-core'

@Controller('protected')
@UseGuards(AuthGuard)
export class ProtectedController {
  @Get()
  getProtectedData() {
    return { message: '这是受保护的数据' }
  }
}

全局应用 AuthGuard

您可以在应用级别全局应用 AuthGuard,这样所有路由默认都会受到保护:

import { Module } from '@nestjs/common'
import { APP_GUARD } from '@nestjs/core'
import { AuthGuard, AuthModule } from '@maxtan/nest-core'

@Module({
  imports: [
    AuthModule.register({
      secret: 'your-jwt-secret-key'
    })
    // 其他模块...
  ],
  providers: [
    {
      provide: APP_GUARD,
      useClass: AuthGuard
    }
  ]
})
export class AppModule {}

当启用全局 AuthGuard 后,可以使用 @AuthPublic() 装饰器来标记不需要认证的公开路由:

import { Controller, Get } from '@nestjs/common'
import { AuthPublic } from '@maxtan/nest-core'

@Controller('public')
export class PublicController {
  @Get()
  @AuthPublic()
  getPublicData() {
    return { message: '这是公开数据,无需认证' }
  }
}

获取当前用户

从请求中获取当前认证用户:

import { Controller, Get, Request, UseGuards } from '@nestjs/common'
import { AuthGuard } from '@maxtan/nest-core'

@Controller('profile')
@UseGuards(AuthGuard)
export class ProfileController {
  @Get()
  getProfile(@Request() req) {
    // req.user 包含了 JWT payload 中的信息
    return req.user
  }
}

使用 AuthDecorator 获取用户信息

更简洁的方式是使用 AuthDecorator 装饰器来直接获取认证用户信息:

import { Controller, Get, UseGuards } from '@nestjs/common'
import { AuthGuard, AuthDecorator } from '@maxtan/nest-core'

@Controller('profile')
@UseGuards(AuthGuard)
export class ProfileController {
  @Get()
  getProfile(@AuthDecorator() auth) {
    // auth 包含完整的认证用户信息
    return auth
  }

  @Get('username')
  getUsername(@AuthDecorator('username') username: string) {
    // 直接获取指定字段
    return { username }
  }

  @Get('data')
  getData(@AuthDecorator('data') data: any) {
    // 获取自定义数据字段
    return data
  }
}

AuthDecorator 可以接受一个可选的参数,用于指定要获取的 JWT payload 中的字段名。如果不提供参数,将返回整个认证对象。

JWT Token 自定义扩展

@maxtan/nest-core 的认证模块只负责 验证和解析 JWT token,不干涉 token 的生成和加密逻辑。

你可以在外部应用中自由定义 JWT payload 结构和加密方式:

import { JwtService } from '@nestjs/jwt'
import { Injectable } from '@nestjs/common'

@Injectable()
export class AuthService {
  constructor(private jwtService: JwtService) {}

  // 自定义 token 生成逻辑
  async generateToken(user: any) {
    // 自定义 payload 结构
    const payload = {
      sub: user.id, // 标准字段
      username: user.username, // 业务字段
      roles: user.roles, // 自定义字段
      permissions: user.perms, // 自定义字段
      customData: {
        // 任意嵌套结构
        department: user.dept,
        level: user.level
      }
    }

    // 使用自己的加密方式
    return this.jwtService.sign(payload, {
      algorithm: 'RS256', // 支持 RSA 非对称加密
      expiresIn: '7d'
      // 更多自定义配置...
    })
  }
}

支持的自定义选项

  1. Payload 结构:任意自定义字段,AuthPayload 类型支持索引签名
  2. 加密算法:支持 HS256、HS384、HS512、RS256、RS384、RS512 等
  3. 签名密钥:支持对称密钥和 RSA 非对称密钥
  4. 过期策略:自定义 expiresInnotBefore
  5. 多租户支持:通过 issaud 字段实现

AuthGuard 会自动解析你的自定义 payload,并注入到 request.user 中:

@Get('profile')
getProfile(@AuthDecorator() auth) {
  // 可以访问所有自定义字段
  console.log(auth.roles)        // 自定义字段
  console.log(auth.permissions)  // 自定义字段
  console.log(auth.customData)   // 嵌套对象
  return auth
}

TypeORM 实体基类

TypeOrmDocument 是一个基础实体类,提供了常用的审计字段和自动时间戳管理功能。

基础使用

import { Entity, PrimaryColumn } from 'typeorm'
import { TypeOrmDocument } from '@maxtan/nest-core'

@Entity('users')
export class User extends TypeOrmDocument {
  @PrimaryColumn({ type: 'bigint' })
  id: string

  @Column()
  username: string

  @Column()
  email: string
}

继承 TypeOrmDocument 后,实体会自动拥有以下字段:

字段名 数据库列名 数据库类型 应用层类型 说明
createdAt create_at bigint number 创建时间(毫秒时间戳),插入时自动设置
createBy create_by varchar string 创建者(可为空),需手动设置
updateAt update_at bigint number 更新时间(毫秒时间戳),插入或更新时自动设置
updateBy update_by varchar string 更新者(可为空),需手动设置
deletedAt deleted_at bigint string 删除时间(软删除标记),默认不返回(需显式查询)

自动时间戳

TypeOrmDocument 使用 TypeORM 的生命周期钩子自动管理时间戳:

// 插入时
const user = new User()
user.username = 'john'
// createdAt 和 updateAt 会自动设置为当前时间
await repository.save(user)

// 更新时
user.email = 'john@example.com'
// updateAt 会自动更新为当前时间,createdAt 保持不变
await repository.save(user)

软删除支持

deletedAt 字段用于软删除功能,默认设置了 select: false 和索引,不会在查询时自动返回:

import { IsNull, Not } from 'typeorm'

// 查询未删除的记录(推荐)
// 由于 deletedAt 默认 select: false,不需要额外过滤
const activeUsers = await repository.find()

// 如需显式过滤未删除记录
const activeUsers = await repository.find({
  where: { deletedAt: IsNull() }
})

// 查询已删除的记录(需显式选择 deletedAt)
const deletedUsers = await repository.find({
  where: { deletedAt: Not(IsNull()) },
  select: ['id', 'username', 'deletedAt'], // 必须显式指定
  withDeleted: true // TypeORM 选项
})

// 软删除(手动设置 deletedAt)
user.deletedAt = String(Date.now()) // 注意:deletedAt 是 string 类型
await repository.save(user)

// 恢复软删除的记录
user.deletedAt = null
await repository.save(user)

注意事项

  • deletedAt 字段类型为 string(不是 number),设置时需转换
  • 默认 select: false,查询已删除记录时必须显式指定
  • 该字段已建立索引,查询性能良好

时间戳转换

时间戳字段在数据库中存储为 bigint 类型,在应用层通过 TypeOrmTimeTransformer 转换器自动转换为 number 类型:

import { TypeOrmTimeTransformer } from '@maxtan/nest-core'

// TypeOrmTimeTransformer 自动处理 bigint 和 number 之间的转换
// - 存入数据库:number -> bigint
// - 从数据库读取:bigint -> number

const user = await repository.findOne({ where: { id: '123' } })
console.log(user.createdAt) // 1700000000000 (number)
console.log(typeof user.createdAt) // "number"

// 可以直接用于 JSON 响应和日期转换
return user // 自动序列化为数字
const date = new Date(user.createdAt) // 直接转换,无需 Number()

自定义创建者和更新者

你可以在业务逻辑中手动设置创建者和更新者:

// 创建时设置创建者
const user = new User()
user.username = 'john'
user.createBy = currentUserId // 手动设置
await repository.save(user)

// 更新时设置更新者
user.email = 'john@example.com'
user.updateBy = currentUserId // 手动设置
await repository.save(user)

或者结合拦截器自动设置:

import { Injectable, NestInterceptor, ExecutionContext, CallHandler } from '@nestjs/common'
import { Observable } from 'rxjs'
import { tap } from 'rxjs/operators'

@Injectable()
export class AuditInterceptor implements NestInterceptor {
  intercept(context: ExecutionContext, next: CallHandler): Observable<any> {
    const request = context.switchToHttp().getRequest()
    const userId = request.user?.id // 从认证信息中获取用户ID

    return next.handle().pipe(
      tap((data) => {
        // 在保存实体前设置审计字段
        if (data && userId) {
          if (!data.createBy) data.createBy = userId
          data.updateBy = userId
        }
      })
    )
  }
}

雪花算法

雪花算法用于生成全局唯一的分布式 ID,基于 @sapphire/snowflake 实现:

基础使用

import { createSnowflake } from '@maxtan/nest-core'

// 创建默认雪花算法实例
const snowflake = createSnowflake()

// 生成唯一ID
const id = snowflake.generateSnowflakeId()
console.log(id) // 输出类似: "1234567890123456789"

自定义配置

import { createSnowflake } from '@maxtan/nest-core'

// 自定义工作节点ID和起始时间
const snowflake = createSnowflake({
  workerId: 1, // 工作节点ID
  epoch: new Date('2024-01-01T00:00:00.000Z') // 自定义起始时间
})

const id = snowflake.generateSnowflakeId()

支持的配置选项

interface SnowflakeOptions {
  workerId?: number // 工作节点ID,默认为1
  epoch?: number | string | Date // 起始时间,默认为2024-01-01 00:00:00 UTC
}

实例缓存

相同配置参数的实例会被自动缓存,避免重复创建:

// 这两个调用会返回同一个实例
const snowflake1 = createSnowflake({ workerId: 1 })
const snowflake2 = createSnowflake({ workerId: 1 })

console.log(snowflake1 === snowflake2) // true

异常过滤器

异常过滤器会捕获应用中的所有异常,并以统一的格式返回响应,同时记录详细的错误日志:

import { APP_FILTER } from '@nestjs/core'
import { AllExceptionsFilter } from '@maxtan/nest-core'

@Module({
  providers: [
    {
      provide: APP_FILTER,
      useClass: AllExceptionsFilter
    }
  ]
})
export class AppModule {}

配置参考

AllLoggerOptions

参数 类型 描述
useConsole boolean 是否输出到控制台,默认 true
maxDays number 日志文件保留天数,默认 30 天
maxSize string 单个日志文件最大大小,默认 '20m'
sls SlsAppenderOptions 阿里云 SLS 配置(可选)

SlsAppenderOptions

参数 类型 描述
accessKeyId string 阿里云访问密钥ID
accessKeySecret string 阿里云访问密钥密码
endpoint string SLS服务端点,默认'cn-hangzhou.log.aliyuncs.com'
projectName string SLS项目名称
logStoreName string SLS日志存储名称
topic string 日志主题,默认'nest-boot'
source string 日志来源,默认'source'
env string 环境标识,默认'production'

AuthModuleOptions

参数 类型 描述
secret string 用于签名 JWT 的密钥
signOptions JwtSignOptions JWT 签名选项,包含过期时间、发行方等配置

SnowflakeOptions

参数 类型 描述
workerId number 工作节点ID,用于分布式环境中区分不同节点
epoch number | string | Date 起始时间,默认为2025-01-01 00:00:00 UTC

最佳实践

  1. 在启动时配置全局日志:使用 createLogger 函数在应用初始化时配置日志系统,确保所有日志都能被正确捕获。

  2. 使用不同的日志级别:根据信息的重要程度选择合适的日志级别,如调试信息使用 debug,错误信息使用 error 等。

  3. 区分环境配置

    • 开发环境:启用控制台日志,使用较低的日志级别(如 debug)
    • 生产环境:可关闭控制台日志,使用较高的日志级别(如 info 或 warn),启用 SLS 日志
  4. 合理设置日志保留期:根据存储空间和审计要求设置合适的 maxDays 值,默认 30 天,并启用日志压缩。

  5. 错误处理结合异常过滤器:使用 AllExceptionsFilter 统一处理异常,确保所有异常都被正确记录,并带有错误追踪 ID。

  6. 利用阿里云 SLS 进行日志分析:在生产环境中使用阿里云 SLS 进行集中式日志管理和分析,方便问题排查。

  7. 合理使用缓存

    • 对频繁访问但不常变化的数据使用缓存
    • 设置合理的过期时间
    • 使用 setObject/getObject 自动处理 JSON 序列化
    • 利用批量操作(mget/mset)提升性能
  8. 操作日志记录最佳实践

    • 通过 OperationModule.forRoot() 全局启用自动日志记录
    • 使用 excludePaths 排除健康检查、监控等不需要记录的路径
    • 全局不启用 requestresponse,避免日志过大
    • 对重要操作使用 @Operation 装饰器按需启用请求和响应记录
    • 利用自动脱敏保护敏感信息
    • 利用 operationId 关联业务日志和错误堆栈
  9. 授权与认证安全

    • 使用足够长且复杂的 JWT 密钥
    • 设置合理的 Token 过期时间
    • 考虑在生产环境中使用非对称加密算法(RS256)
    • 实现 Token 刷新机制以提高安全性
    • 利用多种 Token 提取策略支持不同场景
  10. 雪花算法使用建议

    • 在分布式环境中为不同节点设置不同的 workerId
    • 确保各节点的系统时间同步,避免时钟回拨问题
    • 根据业务需求选择合适的起始时间(epoch)
    • 利用实例缓存特性,避免重复创建相同配置的实例
    • 使用加密安全的随机数生成器
  11. 数据验证优化

    • 利用增强的 ValidationPipe 处理嵌套对象验证
    • 根据需要设置 showAllErrors 显示所有错误
    • 使用自定义错误分隔符优化错误显示
  12. 事务管理

    • 使用 runInTransaction 自动管理事务生命周期
    • 避免手动管理事务的提交、回滚和释放
  13. TypeORM 实体设计

    • 继承 TypeOrmDocument 获得标准审计字段(创建时间、更新时间、创建者、更新者、软删除标记)
    • 利用 @BeforeInsert@BeforeUpdate 钩子自动管理时间戳,无需手动设置
    • 时间戳字段在数据库中存储为 bigint,在应用层自动转换为 number,便于计算和 JSON 序列化
    • 使用 deletedAt 实现软删除,保留历史数据(注意:deletedAtstring 类型)
    • deletedAt 默认不返回(select: false),查询已删除记录时需显式指定
    • 结合拦截器或装饰器自动设置 createByupdateBy 字段
    • 所有审计字段均已建立索引,支持高效查询

许可证

ISC