diff --git a/Controllers/AuthController.cs b/Controllers/AuthController.cs index c7a2706..aa32961 100644 --- a/Controllers/AuthController.cs +++ b/Controllers/AuthController.cs @@ -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); diff --git a/Dockerfile b/Dockerfile index 5b45e15..43d5066 100644 --- a/Dockerfile +++ b/Dockerfile @@ -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/* diff --git a/README.md b/README.md index 0697b47..ebcab50 100644 --- a/README.md +++ b/README.md @@ -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` 或挂载配置文件实现。 --- diff --git a/Services/DatabaseInitializer.cs b/Services/DatabaseInitializer.cs index 0dfd737..8d9f298 100644 --- a/Services/DatabaseInitializer.cs +++ b/Services/DatabaseInitializer.cs @@ -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 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); + } }