发布 0.1.0:通知渠道、告警规则、令牌版本与安全加固
CI / test (push) Successful in 30s
Release / release (push) Successful in 49s

This commit is contained in:
Wang Defa
2026-07-10 17:38:34 +08:00
parent 4af6a0ca92
commit dbba1f4905
78 changed files with 6898 additions and 551 deletions
+38 -10
View File
@@ -81,7 +81,7 @@ func (h *authxHandler) totpActivate(c *gin.Context) {
respondError(c, err)
return
}
c.Status(http.StatusNoContent)
h.respondFreshToken(c)
}
// totpDisable 停用两步验证;需当前验证码或登录密码任一确认。
@@ -110,7 +110,34 @@ func (h *authxHandler) totpDisable(c *gin.Context) {
respondError(c, err)
return
}
c.Status(http.StatusNoContent)
h.respondFreshToken(c)
}
// respondFreshToken 敏感变更后为操作者签发新令牌返回(版本已递增,
// 旧令牌全部失效);签发失败降级 204,前端按会话失效走重新登录。
func (h *authxHandler) respondFreshToken(c *gin.Context) {
token, expires, err := h.auth.IssueToken(c.Request.Context(), c.GetString(usernameKey))
if err != nil {
c.Status(http.StatusNoContent)
return
}
c.JSON(http.StatusOK, gin.H{"token": token, "expiresAt": expires})
}
// revokeSessions 撤销全部会话(令牌版本递增),并为当前操作者重签新令牌。
//
// @Summary 撤销全部会话
// @Tags 认证
// @Success 200 {object} map[string]string "新 token 与 expiresAt"
// @Security BearerAuth
// @Router /api/v1/auth/revoke-sessions [post]
func (h *authxHandler) revokeSessions(c *gin.Context) {
token, expires, err := h.auth.RevokeSessions(c.Request.Context(), c.GetString(usernameKey))
if err != nil {
respondError(c, err)
return
}
c.JSON(http.StatusOK, gin.H{"token": token, "expiresAt": expires})
}
// ---- 登录凭据(JWT 组内) ----
@@ -149,7 +176,7 @@ func (h *authxHandler) updateCredentials(c *gin.Context) {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}
err := h.auth.UpdateCredentials(c.Request.Context(), c.GetString(usernameKey), req)
finalName, err := h.auth.UpdateCredentials(c.Request.Context(), c.GetString(usernameKey), req)
if errors.Is(err, service.ErrCredentialConfirm) {
c.JSON(http.StatusUnauthorized, gin.H{"error": err.Error()})
return
@@ -162,7 +189,8 @@ func (h *authxHandler) updateCredentials(c *gin.Context) {
respondError(c, err)
return
}
c.Status(http.StatusNoContent)
c.Set(usernameKey, finalName)
h.respondFreshToken(c)
}
// updatePasswordLogin 保存密码登录禁用开关;开启需至少绑定一个外部身份。
@@ -191,7 +219,7 @@ func (h *authxHandler) updatePasswordLogin(c *gin.Context) {
respondError(c, err)
return
}
c.Status(http.StatusNoContent)
h.respondFreshToken(c)
}
// ---- OAuth ----
@@ -254,7 +282,7 @@ func (h *authxHandler) bearerUser(c *gin.Context) (string, bool) {
if len(header) < 8 || header[:7] != "Bearer " {
return "", false
}
username, err := h.auth.ParseToken(header[7:])
username, err := h.auth.ParseToken(c.Request.Context(), header[7:])
if err != nil {
return "", false
}
@@ -282,9 +310,9 @@ func (h *authxHandler) oauthCallback(c *gin.Context) {
c.Redirect(http.StatusFound, target+"?oauthError="+url.QueryEscape(oauthErrText(err)))
return
}
if token == "" {
// 绑定模式:回设置页安全 tab
c.Redirect(http.StatusFound, "/settings?oauth=bound")
if mode == "bind" {
// 绑定模式:版本已递增,新 token 经 fragment 带回设置页无感换发
c.Redirect(http.StatusFound, "/settings?oauth=bound#oauthToken="+url.QueryEscape(token))
return
}
// 登录模式:token 放 fragment,不进服务端日志与 Referer
@@ -340,7 +368,7 @@ func (h *authxHandler) unbindIdentity(c *gin.Context) {
respondError(c, err)
return
}
c.Status(http.StatusNoContent)
h.respondFreshToken(c)
}
// ---- OAuth provider 设置(JWT 组内) ----