多用户与角色:owner / admin / reader 三级,用户管理页 + 密码上库
- users 表加 password_hash 列;后台账号(owner+admin)密码 bcrypt 存行内, 首次登录把 env / settings 引导凭据自迁移成行哈希 - 会话 token 从用户名改为携带用户 ID,角色与停用状态每请求查库, 改角色 / 停用账号即时生效(存量会话立即 401) - 登录:先查 users 表,再走 settings 哈希 / env 引导链; admin/admin 开发模式在任何账号设过密码后失效 - 权限:系统设置、用户管理仅 owner;内容管理 admin+owner; admin 后台新增 用户 页(创建 / 重置密码 / 停用 / 删除), 设置页「登录与存储」tab 对管理员隐藏 - 账户页加修改密码表单(旧密码校验,OAuth/Passkey 首设免旧密码); 评论区管理员身份跟随各自账号,不再统一挂站主名下 - 修复:providers 为 nil 时账户页白屏(Go nil slice 序列化成 null)
This commit is contained in:
1 parent
e5dee4daf1
commit
4bb2ff4145
23 files changed
+917
-222
No files matched your search
@@ -34,20 +34,12 @@ type accountView struct {
|
||||
}
|
||||
|
||||
type passwordInfo struct {
|
||||
// 密码现在有两个可能的家:settings 表里的 bcrypt 哈希(后台改的),
|
||||
// 或环境变量 ONE_ADMIN_PASSWORD(未迁移时的兜底)。
|
||||
// 多用户后密码统一在 users 行上(bcrypt),在账户页修改。
|
||||
// 首次登录时 env / settings 的引导凭据会自迁移成行内哈希。
|
||||
ManagedBy string `json:"managed_by"`
|
||||
Username string `json:"username"`
|
||||
}
|
||||
|
||||
// passwordSource 报告当前密码存哪。前端只作展示,不参与逻辑。
|
||||
func passwordSource(hash string) string {
|
||||
if hash != "" {
|
||||
return "settings"
|
||||
}
|
||||
return "env:ONE_ADMIN_PASSWORD"
|
||||
}
|
||||
|
||||
func (a *API) account(w http.ResponseWriter, r *http.Request) {
|
||||
if r.Method != http.MethodGet {
|
||||
httpx.Error(w, http.StatusMethodNotAllowed, "GET required")
|
||||
@@ -79,15 +71,16 @@ func (a *API) buildAccount() (accountView, error) {
|
||||
return accountView{}, err
|
||||
}
|
||||
v := accountView{
|
||||
// Providers 必须非 nil:一个第三方都没配时 Go 会序列化成 null,
|
||||
// 前端 acct.providers.length 直接炸(真实事故:新库未配 OAuth 时账户页白屏)
|
||||
Providers: []string{},
|
||||
// 昵称以站主行的 name 为准;老数据里它是空的,回落到站点设置的作者名。
|
||||
Name: firstNonEmptyStr(owner.Name, st.AuthorName),
|
||||
Bio: st.AuthorBio,
|
||||
AvatarKey: st.AuthorAvatarKey,
|
||||
AvatarURL: a.avatarURL(st.AuthorAvatarKey),
|
||||
Handle: owner.Handle,
|
||||
// 密码可迁到哪:后台「管理员账号」里改过就是 DB(bcrypt 哈希),
|
||||
// 否则回落 env。
|
||||
Password: passwordInfo{ManagedBy: passwordSource(st.AdminPasswordHash), Username: a.cfg().AdminUser},
|
||||
Name: firstNonEmptyStr(owner.Name, st.AuthorName),
|
||||
Bio: st.AuthorBio,
|
||||
AvatarKey: st.AuthorAvatarKey,
|
||||
AvatarURL: a.avatarURL(st.AuthorAvatarKey),
|
||||
Handle: owner.Handle,
|
||||
Password: passwordInfo{ManagedBy: "account", Username: a.cfg().AdminUser},
|
||||
Identities: ids,
|
||||
Passkeys: pks,
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user