feat(auth): 用户账户 - 完善个人资料与登录日志 (#752)

Co-authored-by: wuligao <1247662379@qq.com>
This commit is contained in:
ddcat666
2026-10-13 05:31:30 +08:00
committed by GitHub
parent e70fe1b9c9
commit 4c1d2b4012
83 changed files with 5836 additions and 328 deletions

View File

@@ -22,6 +22,7 @@ import (
func RegisterAuthRoutes(r *gin.RouterGroup, svc *service.Service) {
registerChannelOrderRoutes(r, svc)
registerNotificationRoutes(r, svc)
registerAuthProfileRoutes(r, svc)
r.GET("/auth/settings", func(c *gin.Context) {
settings, err := svc.PublicAuthSettings()
if err != nil {
@@ -41,6 +42,7 @@ func RegisterAuthRoutes(r *gin.RouterGroup, svc *service.Service) {
if !available || !enforceRateLimit(c, "register:"+c.ClientIP(), policy.Request.RegisterPerHour, time.Hour) {
return
}
req.LoginContext = loginRequestContext(c)
result, err := svc.Register(req)
if err != nil {
failService(c, err)
@@ -113,7 +115,7 @@ func RegisterAuthRoutes(r *gin.RouterGroup, svc *service.Service) {
}
ok(c, gin.H{"reset": true})
})
r.POST("/auth/login", func(c *gin.Context) {
r.POST("/auth/login", rejectedLoginAudit(svc, "password"), func(c *gin.Context) {
c.Request.Body = http.MaxBytesReader(c.Writer, c.Request.Body, 64<<10)
var req service.LoginRequest
if err := c.ShouldBindJSON(&req); err != nil {
@@ -132,6 +134,8 @@ func RegisterAuthRoutes(r *gin.RouterGroup, svc *service.Service) {
if !enforceRateLimit(c, "login:"+c.ClientIP()+":"+subject, policy.Request.LoginAccountPerTenMinutes, 10*time.Minute) {
return
}
req.LoginContext = loginRequestContext(c)
c.Set("login_audit_handled", true)
result, err := svc.Login(req)
if err != nil {
failService(c, err)
@@ -152,9 +156,12 @@ func RegisterAuthRoutes(r *gin.RouterGroup, svc *service.Service) {
}
c.Redirect(http.StatusFound, target)
})
r.GET("/auth/linuxdo/callback", linuxDOCallbackHandler(svc))
r.GET("/auth/linuxdo/callback", rejectedLoginAudit(svc, "linuxdo"), linuxDOCallbackHandler(svc))
r.POST("/auth/logout", func(c *gin.Context) {
_ = svc.Logout(sessionCookie(c))
if err := svc.Logout(sessionCookie(c), loginRequestContext(c)); err != nil {
failService(c, err)
return
}
clearSessionCookie(c)
ok(c, gin.H{"ok": true})
})
@@ -207,7 +214,7 @@ func RegisterAuthRoutes(r *gin.RouterGroup, svc *service.Service) {
// 兼容已在 Linux.do OAuth 应用中登记的传统回调地址,处理逻辑与 /api/auth/linuxdo/callback 完全一致。
func RegisterOAuthCallbackRoutes(r gin.IRoutes, svc *service.Service) {
r.GET("/oauth/linuxdo/callback", linuxDOCallbackHandler(svc))
r.GET("/oauth/linuxdo/callback", rejectedLoginAudit(svc, "linuxdo"), linuxDOCallbackHandler(svc))
}
func linuxDOCallbackHandler(svc *service.Service) gin.HandlerFunc {
@@ -215,12 +222,27 @@ func linuxDOCallbackHandler(svc *service.Service) gin.HandlerFunc {
if !enforceRateLimit(c, "linuxdo-callback:"+c.ClientIP(), 30, 10*time.Minute) {
return
}
result, err := svc.CompleteLinuxDOLogin(c.Query("state"), c.Query("code"))
reauthentication, stateErr := svc.LinuxDOReauthenticationState(c.Query("state"))
if stateErr != nil {
if err := svc.RecordRejectedLogin("linuxdo", loginRequestContext(c), 400); err != nil {
log.Printf("OAuth rejected login audit write failed: error=%v", err)
}
c.Redirect(http.StatusFound, "/login?oauth_error="+url.QueryEscape("无法读取身份验证状态,请重试"))
return
}
c.Set("login_audit_handled", true)
result, err := svc.CompleteLinuxDOLogin(c.Query("state"), c.Query("code"), sessionCookie(c), loginRequestContext(c))
if err != nil {
if reauthentication {
c.Redirect(http.StatusFound, "/settings?section=profile&reauth=error")
return
}
c.Redirect(http.StatusFound, "/login?oauth_error="+url.QueryEscape(err.Error()))
return
}
setSessionCookie(c, result.Session.Session, result.Session.MaxAgeSecs)
if !result.Reauthenticated {
setSessionCookie(c, result.Session.Session, result.Session.MaxAgeSecs)
}
c.Redirect(http.StatusFound, result.Next)
}
}
@@ -230,6 +252,7 @@ func RegisterAdminRoutes(r *gin.RouterGroup, svc *service.Service) {
registerAdminChannelRoutes(r, svc)
registerAdminSettingRoutes(r, svc)
registerAdminAPILogRoutes(r, svc)
registerAdminLoginLogRoutes(r, svc)
}
func RegisterSystemProxyRoutes(r *gin.RouterGroup, svc *service.Service) {