系统设置迁入后台:站点地址 / 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

+8 -8
View File
@@ -58,22 +58,22 @@ func (a *API) beginBind(w http.ResponseWriter, r *http.Request) {
setBindCookie(w)
switch provider {
case "github":
if !a.GH.Enabled() {
if !a.gh().Enabled() {
clearBindCookie(w)
httpx.NotFound(w)
return
}
a.startOAuth(w, r, func(state string) string {
return a.GH.LoginURL(a.Cfg.SiteURL+"/api/auth/callback/github", state)
return a.gh().LoginURL(a.siteURL()+"/api/auth/callback/github", state)
})
case "google":
if !a.GG.Enabled() {
if !a.gg().Enabled() {
clearBindCookie(w)
httpx.NotFound(w)
return
}
a.startOAuth(w, r, func(state string) string {
return a.GG.LoginURL(a.Cfg.SiteURL+"/api/auth/callback/google", state)
return a.gg().LoginURL(a.siteURL()+"/api/auth/callback/google", state)
})
default:
clearBindCookie(w)
@@ -121,7 +121,7 @@ func (a *API) afterIdentity(w http.ResponseWriter, r *http.Request, provider, ex
}
if bindRequested(r) {
owner, err := a.Store.EnsureOwner(a.Cfg.AdminUser)
owner, err := a.Store.EnsureOwner(a.cfg().AdminUser)
if err != nil {
httpx.ServerError(w, err)
return ""
@@ -134,7 +134,7 @@ func (a *API) afterIdentity(w http.ResponseWriter, r *http.Request, provider, ex
httpx.ServerError(w, err)
return ""
}
http.Redirect(w, r, strings.TrimRight(a.Cfg.SiteURL, "/")+"/admin/account?bound="+url.QueryEscape(provider), http.StatusFound)
http.Redirect(w, r, strings.TrimRight(a.siteURL(), "/")+"/admin/account?bound="+url.QueryEscape(provider), http.StatusFound)
return ""
}
@@ -173,7 +173,7 @@ func (a *API) issueReaderSession(w http.ResponseWriter, r *http.Request, readerI
// (开发时前端 :3000、后端 :8080 分离,只有它才不会跳错站),
// 没有记录(直接敲 URL 进来的)就回站点根。
func (a *API) loginBack(w http.ResponseWriter, r *http.Request) string {
back := a.Cfg.SiteURL
back := a.siteURL()
if ck, err := r.Cookie(oauthBackCook); err == nil && ck.Value != "" {
if u, err := url.Parse(ck.Value); err == nil && (u.Scheme == "http" || u.Scheme == "https") && u.Host != "" && u.Path == "" {
back = u.Scheme + "://" + u.Host
@@ -187,7 +187,7 @@ func (a *API) loginBack(w http.ResponseWriter, r *http.Request) string {
// 的落点。Secure / SameSite 与密码登录发的 cookie 完全一致,否则 HTTPS 下
// 浏览器会把它当不安全 cookie 丢掉。
func (a *API) issueAdminSession(w http.ResponseWriter, r *http.Request) {
token, exp := a.AdminSessions.Issue(a.Cfg.AdminUser)
token, exp := a.AdminSessions.Issue(a.cfg().AdminUser)
http.SetCookie(w, &http.Cookie{
Name: adminCookieName, Value: token, Path: "/", HttpOnly: true,
Secure: isTLS(r), SameSite: http.SameSiteLaxMode,