From 5a6328561f1038c8945b8792e02f8df49c8e40b0 Mon Sep 17 00:00:00 2001 From: dlandy Date: Mon, 30 Mar 2026 10:36:17 +0800 Subject: [PATCH] update --- docs/DOCKER_RUN_TOOLSSHOW.md | 3 +++ server/.env.example | 2 ++ server/src/prisma/prisma.service.ts | 36 +++++++++++++++++++++++++++-- 3 files changed, 39 insertions(+), 2 deletions(-) diff --git a/docs/DOCKER_RUN_TOOLSSHOW.md b/docs/DOCKER_RUN_TOOLSSHOW.md index 77f997c..e2de9fd 100644 --- a/docs/DOCKER_RUN_TOOLSSHOW.md +++ b/docs/DOCKER_RUN_TOOLSSHOW.md @@ -34,12 +34,15 @@ PORT=3000 DATABASE_URL="file:./dev.db" JWT_ACCESS_SECRET=change_this_access_secret JWT_REFRESH_SECRET=change_this_refresh_secret +DEFAULT_ADMIN_USERNAME=admin +DEFAULT_ADMIN_PASSWORD=admin123456 ``` 说明: - 当前项目 Prisma 使用 `SQLite`(`server/prisma/schema.prisma`)。 - `DATABASE_URL="file:./dev.db"` 对应数据库文件在容器内路径 `/app/server/prisma/dev.db`。 +- 应用启动后会自动检查管理员账号;若 `DEFAULT_ADMIN_USERNAME` 不存在,则自动创建该账号。 ## 3. 构建镜像 diff --git a/server/.env.example b/server/.env.example index 6f70148..b6feba4 100644 --- a/server/.env.example +++ b/server/.env.example @@ -6,6 +6,8 @@ JWT_ACCESS_SECRET=change_this_access_secret JWT_REFRESH_SECRET=change_this_refresh_secret JWT_ACCESS_EXPIRES_IN=2h JWT_REFRESH_EXPIRES_IN=7d +DEFAULT_ADMIN_USERNAME=admin +DEFAULT_ADMIN_PASSWORD=admin123456 GITLAB_BASE_URL= GITLAB_API_BASE= diff --git a/server/src/prisma/prisma.service.ts b/server/src/prisma/prisma.service.ts index ce14bee..708fc16 100644 --- a/server/src/prisma/prisma.service.ts +++ b/server/src/prisma/prisma.service.ts @@ -1,11 +1,16 @@ -import { INestApplication, Injectable, OnModuleInit } from '@nestjs/common'; -import { PrismaClient } from '@prisma/client'; +import { INestApplication, Injectable, Logger, OnModuleInit } from '@nestjs/common'; +import { AdminUserStatus, PrismaClient } from '@prisma/client'; +import argon2 from 'argon2'; +import { randomUUID } from 'crypto'; @Injectable() export class PrismaService extends PrismaClient implements OnModuleInit { + private readonly logger = new Logger(PrismaService.name); + async onModuleInit(): Promise { await this.$connect(); await this.$queryRawUnsafe('PRAGMA journal_mode = WAL;'); + await this.ensureDefaultAdminUser(); } async enableShutdownHooks(app: INestApplication): Promise { @@ -13,4 +18,31 @@ export class PrismaService extends PrismaClient implements OnModuleInit { await app.close(); }); } + + private async ensureDefaultAdminUser(): Promise { + const username = process.env.DEFAULT_ADMIN_USERNAME?.trim() || 'admin'; + const password = process.env.DEFAULT_ADMIN_PASSWORD || 'admin123456'; + + const existingAdmin = await this.adminUser.findUnique({ + where: { username }, + select: { id: true }, + }); + + if (existingAdmin) { + return; + } + + const passwordHash = await argon2.hash(password, { type: argon2.argon2id }); + await this.adminUser.create({ + data: { + id: `u_admin_${randomUUID().replace(/-/g, '')}`, + username, + passwordHash, + displayName: 'System Admin', + status: AdminUserStatus.active, + }, + }); + + this.logger.log(`Default admin user initialized: ${username}`); + } }