
Security News
Axios Maintainer Confirms Social Engineering Attack Behind npm Compromise
Axios compromise traced to social engineering, showing how attacks on maintainers can bypass controls and expose the broader software supply chain.
@meta-1/nest-assets
Advanced tools
NestJS 资源管理模块,支持亚马逊 S3、阿里云 OSS 和 MinIO 对象存储。
npm install @meta-1/nest-assets
所有必需的依赖(包括 AWS S3 SDK、阿里云 OSS SDK 和 MinIO SDK)会自动安装。
import { Module } from '@nestjs/common';
import { AssetsModule } from '@meta-1/nest-assets';
import { StorageProvider } from '@meta-1/nest-types';
@Module({
imports: [
// 使用 S3
AssetsModule.forRoot({
storage: {
provider: StorageProvider.S3,
publicBucket: 'my-public-bucket',
privateBucket: 'my-private-bucket',
expiresIn: '30m' // 支持字符串(如 '30m', '1h', '2d')或数字(毫秒)
},
s3: {
region: 'us-east-1',
accessKeyId: 'your-access-key-id',
secretAccessKey: 'your-secret-access-key',
endpoint: 'https://s3.amazonaws.com' // 可选,用于兼容 S3 的服务
}
}),
// 或使用阿里云 OSS
AssetsModule.forRoot({
storage: {
provider: StorageProvider.OSS,
publicBucket: 'my-public-bucket',
privateBucket: 'my-private-bucket',
expiresIn: '30m'
},
oss: {
region: 'oss-cn-hangzhou',
accessKeyId: 'your-access-key-id',
accessKeySecret: 'your-secret-access-key'
}
}),
// 或使用 MinIO
AssetsModule.forRoot({
storage: {
provider: StorageProvider.MINIO,
publicBucket: 'my-public-bucket',
privateBucket: 'my-private-bucket',
expiresIn: '30m'
},
minio: {
endpoint: 'http://localhost:9000', // 支持 http://host:port 或 https://host:port 格式
accessKeyId: 'your-access-key-id',
secretAccessKey: 'your-secret-access-key',
useSSL: false, // 可选,默认 false。也可以通过 endpoint 的协议自动推断
region: 'us-east-1' // 可选,默认 'us-east-1'
}
})
]
})
export class AppModule {}
// main.ts
import { NestFactory } from '@nestjs/core';
import { ConfigLoader, ConfigSourceType } from '@meta-1/nest-common';
interface AppConfig {
assets: AssetsConfig;
}
async function bootstrap() {
// 加载配置
const loader = new ConfigLoader<AppConfig>({
type: ConfigSourceType.LOCAL_YAML,
filePath: './config/app.yaml'
});
const config = await loader.load();
// 创建模块
@Module({
imports: [AssetsModule.forRoot(config.assets)]
})
class AppModule {}
const app = await NestFactory.create(AppModule);
await app.listen(3000);
}
bootstrap();
配置文件示例 (config/app.yaml):
assets:
storage:
provider: s3 # 's3' | 'oss' | 'minio'
publicBucket: my-public-bucket
privateBucket: my-private-bucket
expiresIn: 30m
s3:
region: us-east-1
accessKeyId: ${AWS_ACCESS_KEY_ID}
secretAccessKey: ${AWS_SECRET_ACCESS_KEY}
endpoint: ${AWS_S3_ENDPOINT} # 可选
oss:
region: oss-cn-hangzhou
accessKeyId: ${ALIYUN_ACCESS_KEY_ID}
accessKeySecret: ${ALIYUN_ACCESS_KEY_SECRET}
minio:
endpoint: ${MINIO_ENDPOINT} # 支持 http://host:port 或 https://host:port 格式
accessKeyId: ${MINIO_ACCESS_KEY_ID}
secretAccessKey: ${MINIO_SECRET_ACCESS_KEY}
useSSL: false # 可选,默认 false
region: us-east-1 # 可选,默认 'us-east-1'
重要: AssetsModule 只提供 Service,Controller 需要由业务方实现。这样可以添加权限控制、日志等业务逻辑。
// src/controllers/assets.controller.ts
import { Body, Controller, Post, UseGuards } from '@nestjs/common';
import { ApiTags, ApiOperation, ApiBearerAuth } from '@nestjs/swagger';
import { JwtAuthGuard } from '@/guards/jwt-auth.guard';
import {
AssetsService,
PresignedUploadUrlRequest,
PresignedUploadUrlResponse,
PresignedDownloadUrlRequest,
PresignedDownloadUrlResponse,
} from '@meta-1/nest-assets';
@ApiTags('Assets')
@Controller('api/assets')
@UseGuards(JwtAuthGuard) // ✅ 添加权限验证
@ApiBearerAuth()
export class AssetsController {
constructor(private readonly assetsService: AssetsService) {}
@Post('presigned-upload-url')
@ApiOperation({ summary: '生成预签名上传 URL' })
async generatePresignedUploadUrl(
@Body() request: PresignedUploadUrlRequest
): Promise<PresignedUploadUrlResponse> {
return this.assetsService.generatePresignedUploadUrl(request);
}
@Post('presigned-download-url')
@ApiOperation({ summary: '生成预签名下载 URL' })
async generatePresignedDownloadUrl(
@Body() request: PresignedDownloadUrlRequest
): Promise<PresignedDownloadUrlResponse> {
return this.assetsService.generatePresignedDownloadUrl(request);
}
}
然后在 AppModule 中注册:
@Module({
imports: [AssetsModule],
controllers: [AssetsController], // ✅ 注册业务方的 Controller
})
export class AppModule {}
更多示例: 查看 CONTROLLER_EXAMPLE.md 了解如何添加权限控制、日志、限流等功能。
import { Injectable } from '@nestjs/common';
import { AssetsService, BucketType } from '@meta-1/nest-assets';
@Injectable()
export class MyService {
constructor(private readonly assetsService: AssetsService) {}
async uploadFile() {
// 生成预签名上传 URL
const uploadUrl = await this.assetsService.generatePresignedUploadUrl({
fileName: 'example.jpg',
contentType: 'image/jpeg',
bucketType: BucketType.PUBLIC, // 或 BucketType.PRIVATE
prefix: 'images', // 可选,文件路径前缀
});
// 返回给客户端
return {
uploadUrl: uploadUrl.uploadUrl, // 客户端用此 URL 上传文件
fileUrl: uploadUrl.fileUrl, // 上传成功后的访问地址
fileKey: uploadUrl.fileKey, // 文件唯一标识
expiresAt: uploadUrl.expiresAt, // 过期时间
};
}
async downloadFile(fileUrl: string) {
// 生成预签名下载 URL
// 如果是公桶,直接返回原 URL
// 如果是私桶,返回带签名的临时 URL
const downloadUrl = await this.assetsService.generatePresignedDownloadUrl({
url: fileUrl,
});
return downloadUrl;
}
}
使用内置的 Controller:
# 生成上传 URL
POST /assets/presigned-upload-url
Content-Type: application/json
{
"fileName": "example.jpg",
"contentType": "image/jpeg",
"bucketType": "public",
"prefix": "images"
}
# 生成下载 URL
POST /assets/presigned-download-url
Content-Type: application/json
{
"url": "http://meta1top:30900/wiki-private/1234567890_abc_example.jpg"
}
注意: 所有请求参数都会自动进行类型验证,Swagger UI 会显示完整的 Schema 信息。
// 1. 获取预签名上传 URL
const { uploadUrl, fileUrl } = await fetch('/assets/presigned-upload-url', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
fileName: 'example.jpg',
contentType: 'image/jpeg',
bucketType: 'public',
}),
}).then(res => res.json());
// 2. 使用预签名 URL 上传文件
await fetch(uploadUrl, {
method: 'PUT',
headers: { 'Content-Type': 'image/jpeg' },
body: fileBlob,
});
// 3. 上传成功后,使用 fileUrl 访问文件
console.log('文件地址:', fileUrl);
模块支持两种桶类型,通过 BucketType 枚举指定,系统会自动将文件存储到对应的桶中:
公桶 (BucketType.PUBLIC):
storage.publicBucket 配置的桶中私桶 (BucketType.PRIVATE):
storage.privateBucket 配置的桶中assets:
storage:
provider: s3
publicBucket: my-public-bucket # 公共文件存储桶
privateBucket: my-private-bucket # 私密文件存储桶
expiresIn: 30m
当调用 API 时指定 bucketType: "public" 或 bucketType: "private",文件会自动存储到对应的桶中。
generatePresignedUploadUrl(request)生成预签名上传 URL。
参数:
fileName: 文件名contentType: 文件 MIME 类型bucketType: 桶类型 (BucketType.PUBLIC | BucketType.PRIVATE)prefix: 可选,文件路径前缀返回:
uploadUrl: 预签名上传 URLfileUrl: 文件访问 URL(公桶可直接访问,私桶需要通过预签名下载 URL 访问)fileKey: 文件唯一标识expiresAt: 过期时间(Unix 时间戳)generatePresignedDownloadUrl(request)生成预签名下载 URL。会自动判断是公桶还是私桶:
参数:
url: 文件完整 URL(从上传接口返回的 url 字段)返回:
downloadUrl: 下载 URL(公桶返回原 URL,私桶返回预签名 URL)expiresAt: 过期时间(0 表示不过期,仅公桶)MIT
FAQs
NestJS assets module for S3 and OSS object storage
We found that @meta-1/nest-assets demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Security News
Axios compromise traced to social engineering, showing how attacks on maintainers can bypass controls and expose the broader software supply chain.

Security News
Node.js has paused its bug bounty program after funding ended, removing payouts for vulnerability reports but keeping its security process unchanged.

Security News
The Axios compromise shows how time-dependent dependency resolution makes exposure harder to detect and contain.