系统设置迁入后台:站点地址 / OAuth 凭据 / R2 存储 / 管理员账号,保存即生效无需重启

- 生效规则统一为「后台填了用后台的,没填回落环境变量」,老部署不改 env 照常跑
- config.Resolver:短缓存解析有效配置,存储后端按配置签名热重建;后台保存主动失效
- 秘密项(client secret / bot token / R2 密钥 / 管理员密码)接口永不回显明文,
  只报「是否已配置、来自哪里」;留空保存 = 保持现值
- 管理员密码 bcrypt 入库,DB 哈希优先、显式设置的 env 密码作解锁后路;
  后台改过密码后 admin/admin 开发模式立即失效
- 设置页新增「登录与存储」标签,基础信息加站点地址;秘密项带来源提示
- 监听地址 / 数据库 / 目录 / ONE_SECRET / Passkey 仍留环境变量(启动期依赖)
This commit is contained in:
Sakurasan committed 2026-10-01 12:14:10 +08:00
1 parent bf3ce934dd
commit e68400b389
23 files changed
+957 -126

No files matched your search

+21 -21
View File
@@ -22,7 +22,6 @@ import (
"oneblog/internal/config"
"oneblog/internal/db"
"oneblog/internal/hub"
"oneblog/internal/storage"
"oneblog/internal/store"
"oneblog/internal/thumbs"
)
@@ -50,18 +49,11 @@ func main() {
log.Fatalf("store: %v", err)
}
// 文件上传的存储后端:R2 配置齐全用 R2,否则本地磁盘兜底。
// 两个 API 共享同一实例;公开访问路由 /uploads/ 也走它。
var blobs storage.BlobStore
switch cfg.StorageDriver {
case "r2":
blobs, err = storage.NewR2(cfg.S3Endpoint, cfg.R2Bucket, cfg.R2AccessKey, cfg.R2SecretKey)
if err != nil {
log.Fatalf("storage: %v", err)
}
default:
blobs = storage.NewLocal(filepath.Join(cfg.DataDir, "uploads"))
}
// 有效配置 = DB 里的系统设置叠加环境变量(DB 优先)。站点地址、
// OAuth 凭据、R2 存储、管理员账号都已迁进后台「设置」页,
// 这里只保留 env 兜底值,改设置不再需要重启。
res := config.NewResolver(cfg, st)
cfgEff := res.Config()
// 评论区的读者会话(cookie one_reader),30 天有效
readerSessions := auth.NewReaderSessions(cfg.SessionSec, 30*24*time.Hour)
@@ -86,19 +78,16 @@ func main() {
public := &api.API{
Store: st,
Cfg: cfg,
Blobs: blobs,
Res: res,
Thumbs: thumbCache,
ReaderSessions: readerSessions,
GH: auth.GitHub{ClientID: cfg.GitHubClientID, ClientSecret: cfg.GitHubClientSecret},
GG: auth.Google{ClientID: cfg.GoogleClientID, ClientSecret: cfg.GoogleClientSecret},
TG: auth.Telegram{Bot: cfg.TelegramBot, Token: cfg.TelegramToken},
AdminSessions: adminSessions,
Passkeys: passkeys,
Hub: commentHub,
}
adminAPI := admin.NewAPI(st, cfg, adminSessions)
adminAPI.Res = res
adminAPI.Hub = commentHub
adminAPI.Blobs = blobs
adminAPI.Thumbs = thumbCache // 删文件时连带清掉它的缩略图
adminAPI.Passkeys = passkeys
@@ -120,10 +109,21 @@ func main() {
go func() {
log.Printf("ONE server listening on %s (db=%s)", cfg.Addr, cfg.Driver)
if cfg.InsecureDev {
log.Printf("admin login: %s / %s (set ONE_ADMIN_PASSWORD to change)", cfg.AdminUser, cfg.AdminPass)
// 登录提示按有效配置报:后台改过密码/用户名后,这里说的是 DB 里的那套
sysSt, err := st.GetSettings()
passNote := "(set ONE_ADMIN_PASSWORD to change)"
if err == nil && sysSt.AdminPasswordHash != "" {
passNote = "(password set in admin settings)"
}
if cfgEff.InsecureDev && (err != nil || sysSt.AdminPasswordHash == "") {
log.Printf("admin login: %s / %s (set ONE_ADMIN_PASSWORD to change)", cfgEff.AdminUser, cfg.AdminPass)
} else {
log.Printf("admin login: %s / (from ONE_ADMIN_PASSWORD)", cfg.AdminUser)
log.Printf("admin login: %s / %s", cfgEff.AdminUser, passNote)
}
if cfgEff.StorageDriver == "r2" {
log.Printf("storage: R2 (%s)", cfgEff.R2Bucket)
} else {
log.Print("storage: local disk (在后台「设置 → 对象存储」配置 R2 后无需重启即生效)")
}
if !dirExists(cfg.WebDist) {
log.Printf("frontend build not found at %s · run `make web` or `make dev` (API still available)", cfg.WebDist)