npm package: @saihu/common
Description: Common utilities for NestJS applications
Author: Aiden Yang
Latest version: 1.5.5

# Common

A collection of common utilities for NestJS applications, including permission guards, operation logging, and other helper utilities.

## Installation

```bash
npm install @saihu/common
```

## 权限与日志记录组件

### PermissionGuard

PermissionGuard 是一个基于 NestJS 的权限守卫，用于验证用户是否有权限访问特定接口。它支持角色验证和权限验证两种方式。

#### 依赖服务

- redis

#### 功能特点

- 支持基于角色(Roles)的权限验证
- 支持基于权限(Perms)的细粒度权限验证
- 支持公共接口标记
- 可配置启用/禁用

#### 使用装饰器

PermissionGuard 通过以下装饰器来定义接口的权限要求：

```typescript
// 标记接口为公共接口，无需登录即可访问
@Public()

// 定义接口需要的角色
@Roles(['admin', 'editor'])

// 定义接口需要的权限
@Perms(['user:read', 'user:write'])
```

#### 配置选项

在 `CommonModuleOptions` 中可以配置 PermissionGuard 的行为：

```typescript
interface CommonModuleOptions {
  // 是否开启权限校验，默认为 true
  usePerms?: boolean;
  // 其他配置...
}
```

#### 使用示例

首先在模块中注册 CommonModule：

```typescript
import { Module } from '@nestjs/common';
import { SaihuCommonModule } from '@saihu/common';

@Module({
  imports: [
    SaihuCommonModule.forRoot({
      name: 'your-app-name',
      usePerms: true, // 启用权限校验
      // 其他配置...
    }),
  ],
})
export class AppModule {}
```

然后在控制器中使用装饰器：

```typescript
import { Controller, Get } from '@nestjs/common';
import { Public, Roles, Perms } from '@saihu/common';

@Controller('users')
@UseGuards(AuthGuard, PermissionGuard)
export class UserController {
  // 公共接口，无需登录
  @Public()
  @Get('public')
  getPublicData() {
    return { message: 'This is public data' };
  }

  // 需要 admin 或 editor 角色
  @Roles(['admin', 'editor'])
  @Get('admin')
  getAdminData() {
    return { message: 'This is admin data' };
  }

  // 需要 user:read 权限
  @Perms(['user:read'])
  @Get(':id')
  getUserById() {
    return { message: 'User data' };
  }
}
```

### OperlogInterceptor

OperlogInterceptor 是一个操作日志拦截器，用于自动记录用户的操作行为，包括请求参数、响应结果、执行时间等信息。它会将日志通过 RabbitMQ 发送到消息队列。

#### 功能特点

- 自动记录 HTTP 请求的详细信息
- 支持白名单配置，可以排除特定 URL
- 记录用户信息、IP 地址、请求参数、响应结果等
- 记录请求处理时间
- 通过 RabbitMQ 异步发送日志

#### 配置选项

在 `CommonModuleOptions` 中可以配置 OperlogInterceptor 的行为：

```typescript
interface CommonModuleOptions {
  // 模块名称，会作为日志标题
  name: string;
  // 是否开启操作日志，默认为 true
  useOperlog?: boolean;
  // 操作日志白名单，符合条件的 URL 不会被记录
  operlogWhitelist?: string[];
  // RabbitMQ 配置
  rabbitmq?: {
    url: string;
  };
  // 其他配置...
}
```

#### 使用示例

在模块中注册 SaihuCommonModule 时配置操作日志：

```typescript
import { Module } from '@nestjs/common';
import { SaihuCommonModule } from '@saihu/common';

@Module({
  imports: [
    SaihuCommonModule.forRoot({
      name: 'your-app-name',
      useOperlog: true, // 启用操作日志
      operlogWhitelist: ['/health', '/metrics'], // 排除健康检查和监控接口
      rabbitmq: {
        url: 'amqp://localhost:5672',
      },
    }),
  ],
})
export class AppModule {}
```

#### 日志内容

操作日志包含以下信息：

- `title`: 应用名称
- `method`: 控制器方法名
- `request_method`: HTTP 请求方法
- `user_agent`: 用户代理
- `oper_name`: 操作人员名称
- `dept_name`: 部门名称
- `oper_url`: 请求 URL
- `oper_ip`: 客户端 IP
- `oper_param`: 请求参数
- `json_result`: 响应结果
- `status`: HTTP 状态码
- `error_msg`: 错误信息（如有）
- `oper_time`: 操作时间
- `cost_time`: 处理耗时

## 模块配置

SaihuCommonModule 支持两种配置方式：同步配置和异步配置。

### 同步配置

```typescript
SaihuCommonModule.forRoot({
  name: 'your-app-name',
  usePerms: true,
  useOperlog: true,
  operlogWhitelist: ['/health'],
  redis: {
    url: 'redis://localhost:6379',
    password: 'your-redis-password',
  },
  rabbitmq: {
    url: 'amqp://localhost:5672',
  },
});
```

### 异步配置

```typescript
SaihuCommonModule.forRootAsync({
  imports: [ConfigModule],
  useFactory: (configService: ConfigService) => ({
    name: configService.get('APP_NAME'),
    operlogWhitelist: configService.get('OPERLOG_WHITELIST')?.split(',') || [],
    redis: {
      url: configService.get('REDIS_URL'),
      password: configService.get('REDIS_PASSWORD')
    },
    rabbitmq: {
      url: configService.get('RABBITMQ_URL')
    }
  }),
  inject: [ConfigService],
  // 需要额外注册全局的APP_INTERCEPTOR
  SaihuCommonModule.withOperlogInterceptor()
})
```