feat: implement database initialization and admin user setup

This commit is contained in:
shiyu
2025-05-19 21:02:43 +08:00
parent 7a93a03903
commit f8bc7baede
4 changed files with 120 additions and 4 deletions

View File

@@ -101,7 +101,7 @@ public class AuthController(IUserService userService, IConfigService configServi
public IActionResult GitHubLogin()
{
string githubClientId = configService["Authentication:GitHubClientId"];
string githubCallback = configService["Authentication:GitHubRedirectUri"];
string githubCallback = configService["Authentication:GitHubCallbackUrl"];
string githubAuthorizeUrl =
$"https://github.com/login/oauth/authorize?client_id={Uri.EscapeDataString(githubClientId)}&redirect_uri={Uri.EscapeDataString(githubCallback)}";
return Redirect(githubAuthorizeUrl);

View File

@@ -26,6 +26,7 @@ RUN dotnet publish "./Foxel.csproj" -c $BUILD_CONFIGURATION -o /app/publish /p:U
FROM base AS final
WORKDIR /app
# Format: Host=yourhost;Username=foxel;Password=foxel;Database=foxel
ENV DEFAULT_CONNECTION="YourDefaultConnectionStringHere"
COPY --from=publish /app/publish .
RUN apt-get update && apt-get install -y nginx && rm -rf /var/lib/apt/lists/*

View File

@@ -52,8 +52,22 @@
打开浏览器访问您的域名或者IP 即可使用 Foxel。
> 如需自定义数据库等配置,可通过修改 `Dockerfile` 或挂载配置文件实现。
4. **获取管理员账号信息**
容器启动后,可通过以下命令查看日志,获取管理员邮箱和初始密码:
```bash
docker logs foxel
```
> ⚠️ **注意:**
> Foxel 依赖 PostgreSQL 数据库,并需要在数据库中启用 [vector 扩展](https://github.com/pgvector/pgvector)。
> 请确保您的 PostgreSQL 实例已正确安装并启用 `vector` 扩展,否则图像检索功能无法正常使用。
> 可通过如下命令在数据库中启用扩展:
> ```sql
> CREATE EXTENSION IF NOT EXISTS vector;
> ```
> 如需自定义数据库等配置,可通过修改 `Dockerfile` 或挂载配置文件实现。
---

View File

@@ -1,6 +1,8 @@
using Foxel.Models.DataBase;
using Foxel.Services.Interface;
using Microsoft.EntityFrameworkCore;
using System.Security.Cryptography;
using System.Text;
namespace Foxel.Services;
@@ -10,16 +12,28 @@ public class DatabaseInitializer(
ILogger<DatabaseInitializer> logger)
: IDatabaseInitializer
{
private const string InitializationFlag = "System:InitializationCompleted";
public async Task InitializeAsync()
{
logger.LogInformation("开始检查数据库初始化状态...");
// 检查是否已经完成初始化
if (await configService.ExistsAsync(InitializationFlag) &&
configService[InitializationFlag] == "true")
{
logger.LogInformation("数据库已完成初始化,跳过初始化步骤");
return;
}
logger.LogInformation("开始初始化数据库配置...");
using var context = await contextFactory.CreateDbContextAsync();
await using var context = await contextFactory.CreateDbContextAsync();
// 确保数据库已创建
await context.Database.EnsureCreatedAsync();
// 初始化JWT配置 -
// 初始化JWT配置
await EnsureConfigExistsAsync("Jwt:SecretKey", "ChAtPiCdEfAuLtSeCrEtKeY2023_Extended_Secure_Key");
await EnsureConfigExistsAsync("Jwt:Issuer", "Foxel");
await EnsureConfigExistsAsync("Jwt:Audience", "FoxelUsers");
@@ -27,6 +41,24 @@ public class DatabaseInitializer(
// 初始化GitHub认证配置
await EnsureConfigExistsAsync("Authentication:GitHubClientId", "placeholder_replace_with_actual_github_client_id");
await EnsureConfigExistsAsync("Authentication:GitHubClientSecret", "placeholder_replace_with_actual_github_client_secret");
await EnsureConfigExistsAsync("Authentication:GitHubClientSecret", "");
// 初始化AI相关配置
await EnsureConfigExistsAsync("AI:ApiEndpoint", "");
await EnsureConfigExistsAsync("AI:ApiKey", "");
await EnsureConfigExistsAsync("AI:Model", "");
await EnsureConfigExistsAsync("AI:EmbeddingModel", "");
// 初始化存储配置
await EnsureConfigExistsAsync("Storage:TelegramStorageBotToken", "");
await EnsureConfigExistsAsync("Storage:TelegramStorageChatId", "");
await EnsureConfigExistsAsync("Storage:DefaultStorage", "Local");
// 初始化其他配置
await EnsureConfigExistsAsync("AppSettings:ServerUrl", "");
// 初始化管理员角色和用户
await InitializeAdminRoleAndUserAsync();
// 标记初始化已完成
await configService.SetConfigAsync(InitializationFlag, "true", "系统初始化完成标志");
logger.LogInformation("数据库配置初始化完成");
}
@@ -39,4 +71,73 @@ public class DatabaseInitializer(
await configService.SetConfigAsync(key, value, $"自动创建的{key}配置");
}
}
private async Task InitializeAdminRoleAndUserAsync()
{
await using var context = await contextFactory.CreateDbContextAsync();
// 检查并创建管理员角色
var adminRole = await context.Roles.FirstOrDefaultAsync(r => r.Name == "Administrator");
if (adminRole == null)
{
logger.LogInformation("创建管理员角色");
adminRole = new Role
{
Name = "Administrator",
Description = "系统管理员角色",
CreatedAt = DateTime.UtcNow,
UpdatedAt = DateTime.UtcNow
};
await context.Roles.AddAsync(adminRole);
await context.SaveChangesAsync();
}
// 检查并创建管理员用户
var adminUser = await context.Users.FirstOrDefaultAsync(u => u.UserName == "Admin");
if (adminUser == null)
{
// 生成随机6位密码
string password = GenerateRandomPassword(6);
string passwordHash = HashPassword(password);
logger.LogInformation("创建管理员用户,用户名: Admin密码: {Password}", password);
adminUser = new User
{
UserName = "Admin",
Email = "you@foxel.cc",
PasswordHash = passwordHash,
RoleId = adminRole.Id,
CreatedAt = DateTime.UtcNow,
UpdatedAt = DateTime.UtcNow
};
await context.Users.AddAsync(adminUser);
Console.ForegroundColor = ConsoleColor.Yellow;
Console.WriteLine($"[重要] 管理员账户初始密码: {password},请及时修改");
Console.ResetColor();
await context.SaveChangesAsync();
}
}
private string GenerateRandomPassword(int length)
{
const string chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
var random = new Random();
var password = new StringBuilder(length);
for (int i = 0; i < length; i++)
{
password.Append(chars[random.Next(chars.Length)]);
}
return password.ToString();
}
private string HashPassword(string password)
{
using var sha256 = SHA256.Create();
var hashedBytes = sha256.ComputeHash(Encoding.UTF8.GetBytes(password));
return Convert.ToBase64String(hashedBytes);
}
}