fix: 改密计入锁定并清理过期管理员会话

This commit is contained in:
Nixevol
2026-09-30 16:22:48 +08:00
parent b3787a0471
commit 1cb562fb71
4 changed files with 108 additions and 2 deletions
+21 -2
View File
@@ -111,6 +111,13 @@ func (h *Handler) handlePassword(w http.ResponseWriter, r *http.Request) {
p, _ := principalFrom(r.Context())
ip := httpx.ClientIP(r, h.trusted)
if locked, retry := h.locks.Check(auth.LockKey{Kind: auth.LockAdminIP, IP: ip}); locked {
w.Header().Set("Retry-After", formatRetryAfter(retry))
h.audit(actorString(p), "password_change", "", "rate_limited", ip)
httpx.WriteError(w, http.StatusTooManyRequests, "rate_limited", "登录已锁定,请稍后再试")
return
}
var req struct {
OldPassword string `json:"old_password"`
NewPassword string `json:"new_password"`
@@ -134,10 +141,18 @@ func (h *Handler) handlePassword(w http.ResponseWriter, r *http.Request) {
}
ok, err := h.hash.Verify(r.Context(), auth.PasswordAdmin, req.OldPassword, phc)
if err != nil || !ok {
locked, retry := h.locks.Fail(auth.LockKey{Kind: auth.LockAdminIP, IP: ip})
if locked {
w.Header().Set("Retry-After", formatRetryAfter(retry))
h.audit(actorString(p), "password_change", "", "rate_limited", ip)
httpx.WriteError(w, http.StatusTooManyRequests, "rate_limited", "登录已锁定,请稍后再试")
return
}
h.audit(actorString(p), "password_change", "", "unauthorized", ip)
httpx.WriteError(w, http.StatusUnauthorized, "unauthorized", "旧密码错误")
return
}
h.locks.Clear(auth.LockKey{Kind: auth.LockAdminIP, IP: ip})
newPHC, err := h.hash.Hash(r.Context(), auth.PasswordAdmin, req.NewPassword)
if err != nil {
h.audit(actorString(p), "password_change", "", "error", ip)
@@ -149,9 +164,13 @@ func (h *Handler) handlePassword(w http.ResponseWriter, r *http.Request) {
httpx.WriteError(w, http.StatusInternalServerError, "internal", "内部错误")
return
}
// 保留当前会话,作废其它会话
// 保留当前会话,作废其它会话;失败则返回 500,避免其它会话继续有效。
if p.Session != "" {
_ = h.deleteOtherSessions(r.Context(), hashSessionHex(p.Session))
if err := h.deleteOtherSessions(r.Context(), hashSessionHex(p.Session)); err != nil {
h.audit(actorString(p), "password_change", "", "error", ip)
httpx.WriteError(w, http.StatusInternalServerError, "internal", "内部错误")
return
}
}
h.audit(actorString(p), "password_change", "", "ok", ip)
httpx.WriteOK(w, map[string]any{})