diff --git a/.env.example b/.env.example index 630cb70..af9449c 100644 --- a/.env.example +++ b/.env.example @@ -7,8 +7,6 @@ FRONTEND_PORT=15173 JWT_SECRET=your_very_secure_jwt_secret_here_change_me_in_production DATA_ENCRYPTION_KEY=your_32_plus_char_data_encryption_key_change_me # 仅用于空数据库的首次启动;已有管理员账号时不会被覆盖。 -INITIAL_ADMIN_USERNAME=skin_nh_admin -INITIAL_ADMIN_PASSWORD=change_me_to_a_secure_password POSTGRES_USER=affiliate POSTGRES_PASSWORD=affiliate_dev_password POSTGRES_DB=affiliate_dash diff --git a/README.md b/README.md index 97e15af..f6d9ac6 100644 --- a/README.md +++ b/README.md @@ -38,7 +38,6 @@ make dev 启动后: - 前端:`http://localhost:15173` - 后端:`http://localhost:18080` -- 空数据库首次启动时由 `INITIAL_ADMIN_USERNAME` / `INITIAL_ADMIN_PASSWORD` 创建平台管理员 按 `Ctrl+C` 停止所有服务。 @@ -61,7 +60,6 @@ make frontend # 前端 :15173 cp .env.example .env # 编辑 .env,确保以下变量已配置: # JWT_SECRET — 生产环境务必修改 -# INITIAL_ADMIN_USERNAME / INITIAL_ADMIN_PASSWORD — 空数据库首次创建的平台管理员,不会覆盖已有账号 # OPEN_API_KEY — 皮肤源头对接 API Key # OPEN_API_SECRET — 签名密钥 # POSTGRES_USER / POSTGRES_PASSWORD / POSTGRES_DB — PostgreSQL 初始化配置 @@ -104,8 +102,6 @@ make docker-down # 停止并移除 | `FRONTEND_PORT` | 前端开发端口 | `15173` | | `HTTP_PORT` / `HTTPS_PORT` | Caddy 对外 HTTP/HTTPS 端口 | `80` / `443` | | `JWT_SECRET` | JWT 签名密钥 | 开发默认值 | -| `INITIAL_ADMIN_USERNAME` | 空数据库首次创建的平台管理员用户名 | 必填(仅首次) | -| `INITIAL_ADMIN_PASSWORD` | 空数据库首次创建的平台管理员密码 | 必填,至少 8 位(仅首次) | | `DATABASE_URL` | PostgreSQL 连接串 | 本地开发默认值 | | `DOCKER_DATABASE_URL` | Docker 后端容器内 PostgreSQL 连接串,通常无需设置 | Compose 内置默认值 | | `POSTGRES_PORT` | PostgreSQL 映射到宿主机的端口 | `15432` | diff --git a/backend/cmd/server/main.go b/backend/cmd/server/main.go index 2b643d1..8e1d998 100644 --- a/backend/cmd/server/main.go +++ b/backend/cmd/server/main.go @@ -84,10 +84,6 @@ func main() { cfg.DeliveryLinkTTLMinutes, ) - if err := authSvc.EnsureAdmin(cfg.InitialAdminUsername, cfg.InitialAdminPassword); err != nil { - log.Fatalf("ensure admin: %v", err) - } - openlog.Init(cfg.OpenAPIDebug) h := &router.Handlers{ @@ -122,7 +118,6 @@ func main() { addr := ":" + cfg.Port log.Printf("游戏皮肤供货平台 API 启动: http://localhost%s", addr) log.Printf("数据库: PostgreSQL") - log.Printf("管理员账号已初始化;请通过账号菜单及时修改初始密码") log.Printf("开放接口鉴权: X-App-Key + X-Timestamp + X-Nonce + X-Sign (HMAC-SHA256)") if cfg.OpenAPIDebug { log.Printf("开放接口调试日志: 开启 (OPEN_API_DEBUG=0 可关闭)") diff --git a/backend/internal/config/config.go b/backend/internal/config/config.go index 1d14888..e64ee2d 100644 --- a/backend/internal/config/config.go +++ b/backend/internal/config/config.go @@ -14,9 +14,6 @@ type Config struct { JWTSecret string DatabaseURL string Mode string // debug / release - // InitialAdminUsername 和 InitialAdminPassword 仅用于空数据库首次创建平台管理员。 - InitialAdminUsername string - InitialAdminPassword string // DataEncryptionKey 用于加密保存 API/回调密钥;为空时由 JWT_SECRET 派生。 DataEncryptionKey string // OpenAPIKey 皮肤源头开放接口标识(Header: X-Api-Key,可公开给对接方) @@ -70,8 +67,6 @@ func Load() *Config { JWTSecret: getEnv("JWT_SECRET", "affiliate-dash-dev-secret-change-me"), DatabaseURL: getEnv("DATABASE_URL", "postgres://affiliate:affiliate_dev_password@127.0.0.1:15432/affiliate_dash?sslmode=disable&TimeZone=Asia/Shanghai"), Mode: mode, - InitialAdminUsername: getEnv("INITIAL_ADMIN_USERNAME", ""), - InitialAdminPassword: getEnv("INITIAL_ADMIN_PASSWORD", ""), DataEncryptionKey: getEnv("DATA_ENCRYPTION_KEY", getEnv("JWT_SECRET", "affiliate-dash-dev-secret-change-me")), OpenAPIKey: getEnv("OPEN_API_KEY", "sk_source_dev_key_change_me"), OpenAPISecret: getEnv("OPEN_API_SECRET", "sk_source_dev_secret_change_me"), diff --git a/backend/internal/service/auth.go b/backend/internal/service/auth.go index 08ce0e9..113fc4f 100644 --- a/backend/internal/service/auth.go +++ b/backend/internal/service/auth.go @@ -153,49 +153,3 @@ func (s *AuthService) UpdateCurrentAccount(userID uint, in UpdateCurrentAccountI } return updated, nil } - -// EnsureAdmin creates the first platform administrator for an empty database. -// Existing administrator accounts are never changed by environment variables. -func (s *AuthService) EnsureAdmin(username, password string) error { - var count int64 - s.db.Model(&model.User{}).Where("role = ?", model.RoleAdmin).Count(&count) - if count > 0 { - if s.tenant != nil { - var admins []model.User - if err := s.db.Where("role = ?", model.RoleAdmin).Find(&admins).Error; err != nil { - return err - } - for _, admin := range admins { - if err := s.tenant.EnsureSelfMember(admin.ID, model.MemberRoleOwner, admin.Status); err != nil { - return err - } - } - } - return nil - } - username = strings.TrimSpace(username) - if len(username) < 3 { - return errors.New("空数据库首次启动必须设置 INITIAL_ADMIN_USERNAME(至少 3 位)") - } - if len(password) < 8 { - return errors.New("空数据库首次启动必须设置 INITIAL_ADMIN_PASSWORD(至少 8 位)") - } - hash, err := bcrypt.GenerateFromPassword([]byte(password), bcrypt.DefaultCost) - if err != nil { - return err - } - admin := &model.User{ - Username: username, - PasswordHash: string(hash), - Nickname: username, - Role: model.RoleAdmin, - Status: 1, - } - if err := s.db.Create(admin).Error; err != nil { - return err - } - if s.tenant != nil { - return s.tenant.EnsureSelfMember(admin.ID, model.MemberRoleOwner, admin.Status) - } - return nil -} diff --git a/backend/internal/service/merchant_test.go b/backend/internal/service/merchant_test.go index ca6f89f..e23259a 100644 --- a/backend/internal/service/merchant_test.go +++ b/backend/internal/service/merchant_test.go @@ -336,26 +336,3 @@ func TestListMerchantAccountGroupsExcludesPlatformAdmins(t *testing.T) { t.Fatalf("unexpected merchant account group: %+v", groups[0]) } } - -func TestEnsureAdminUsesConfiguredCredentialsOnlyForEmptyDatabase(t *testing.T) { - db := newServiceTestDB(t) - tenant := NewTenantService(db) - auth := NewAuthService(db, nil, tenant) - if err := auth.EnsureAdmin("skin_nh_admin", "secure-password"); err != nil { - t.Fatalf("create configured admin: %v", err) - } - var created model.User - if err := db.Where("username = ?", "skin_nh_admin").First(&created).Error; err != nil { - t.Fatalf("configured admin should exist: %v", err) - } - if err := bcrypt.CompareHashAndPassword([]byte(created.PasswordHash), []byte("secure-password")); err != nil { - t.Fatalf("configured password should match: %v", err) - } - if err := auth.EnsureAdmin("replacement-admin", "another-password"); err != nil { - t.Fatalf("existing admin should not be replaced: %v", err) - } - var count int64 - if err := db.Model(&model.User{}).Where("role = ?", model.RoleAdmin).Count(&count).Error; err != nil || count != 1 { - t.Fatalf("existing admin should remain unchanged, count=%d err=%v", count, err) - } -} diff --git a/docker-compose.yml b/docker-compose.yml index 7842be8..d0e4eeb 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -40,8 +40,6 @@ services: - PORT=8080 - TZ=${TZ:-Asia/Shanghai} - JWT_SECRET=${JWT_SECRET} - - INITIAL_ADMIN_USERNAME=${INITIAL_ADMIN_USERNAME:-} - - INITIAL_ADMIN_PASSWORD=${INITIAL_ADMIN_PASSWORD:-} - "DATABASE_URL=${DOCKER_DATABASE_URL:-postgres://${POSTGRES_USER:-affiliate}:${POSTGRES_PASSWORD:-affiliate_dev_password}@postgres:5432/${POSTGRES_DB:-affiliate_dash}?sslmode=disable&TimeZone=${TZ:-Asia/Shanghai}}" - GIN_MODE=${GIN_MODE:-release} - CORS_ALLOWED_ORIGINS=${CORS_ALLOWED_ORIGINS:-}