From 4b2c0052223f05ba01084fa03253b07f7c4928b0 Mon Sep 17 00:00:00 2001 From: Sean Du Date: Sat, 13 Jun 2026 11:27:42 +0800 Subject: [PATCH] Force relogin after webui data changes - Add a force_relogin flag to user_pref - Return 404 for main.php requests when the user must reauthenticate - Clear the relogin flag after successful client login - Mark users for relogin after webui card import, accessory changes, and profile updates Signed-off-by: Sean Du --- internal/handler/login/login.go | 5 +++++ internal/handler/webui/accessory.go | 19 +++++++++++++++++++ internal/handler/webui/profile.go | 16 ++++++++++++++++ internal/handler/webui/upload.go | 5 +++++ internal/middleware/common.go | 20 +++++++++----------- internal/model/user/userpref.go | 20 ++++++++++++++++++++ 6 files changed, 74 insertions(+), 11 deletions(-) diff --git a/internal/handler/login/login.go b/internal/handler/login/login.go index fc09c0f..ced9d65 100644 --- a/internal/handler/login/login.go +++ b/internal/handler/login/login.go @@ -4,6 +4,7 @@ import ( "encoding/base64" "errors" "honoka-chan/internal/middleware" + usermodel "honoka-chan/internal/model/user" "honoka-chan/internal/router" loginschema "honoka-chan/internal/schema/login" "honoka-chan/internal/session" @@ -68,6 +69,10 @@ func login(ctx *gin.Context) { return } + if err := usermodel.ClearUserForceRelogin(ss.UserEng, userID); ss.CheckErr(err) { + return + } + ss.Respond(loginschema.LoginResp{ ResponseData: loginschema.LoginData{ AuthorizeToken: authorizeToken, diff --git a/internal/handler/webui/accessory.go b/internal/handler/webui/accessory.go index 6496eca..72ccb7f 100644 --- a/internal/handler/webui/accessory.go +++ b/internal/handler/webui/accessory.go @@ -23,6 +23,17 @@ type accessoryInventoryItem struct { WornCount int `json:"worn_count"` } +func markAccessoryUserForceRelogin(ctx *gin.Context) bool { + if err := usermodel.MarkUserForceRelogin(db.UserEng, ctx.GetInt("userid")); err != nil { + ctx.JSON(http.StatusOK, webuischema.Msg{ + Code: 1, + Message: "操作成功,但登录状态刷新失败!", + }) + return false + } + return true +} + func accessoryPage(ctx *gin.Context) { ctx.HTML(http.StatusOK, "admin/accessory.html", gin.H{ "menu": 3, @@ -121,6 +132,10 @@ func addAccessory(ctx *gin.Context) { return } + if !markAccessoryUserForceRelogin(ctx) { + return + } + ctx.JSON(http.StatusOK, webuischema.Msg{ Code: 0, Message: "添加成功,请重新进入游戏查看!", @@ -322,6 +337,10 @@ func deleteAccessory(ctx *gin.Context) { return } + if !markAccessoryUserForceRelogin(ctx) { + return + } + ctx.JSON(http.StatusOK, webuischema.Msg{ Code: 0, Message: "删除成功,请重新登录游戏生效!", diff --git a/internal/handler/webui/profile.go b/internal/handler/webui/profile.go index a5e9d5c..b73dce9 100644 --- a/internal/handler/webui/profile.go +++ b/internal/handler/webui/profile.go @@ -147,6 +147,14 @@ func updateProfile(ctx *gin.Context) { return } + if err := usermodel.MarkUserForceRelogin(db.UserEng, ctx.GetInt("userid")); err != nil { + ctx.JSON(http.StatusOK, webuischema.Msg{ + Code: 1, + Message: "保存成功,但登录状态刷新失败!", + }) + return + } + ctx.JSON(http.StatusOK, webuischema.Msg{ Code: 0, Message: "保存成功!", @@ -195,6 +203,14 @@ func resetProfile(ctx *gin.Context) { return } + if err := usermodel.MarkUserForceRelogin(db.UserEng, ctx.GetInt("userid")); err != nil { + ctx.JSON(http.StatusOK, webuischema.Msg{ + Code: 1, + Message: "重置成功,但登录状态刷新失败!", + }) + return + } + ctx.JSON(http.StatusOK, webuischema.Msg{ Code: 0, Message: "已恢复默认值!", diff --git a/internal/handler/webui/upload.go b/internal/handler/webui/upload.go index e830e3e..fe439da 100644 --- a/internal/handler/webui/upload.go +++ b/internal/handler/webui/upload.go @@ -111,6 +111,11 @@ func upload(ctx *gin.Context) { return } + if err := usermodel.MarkUserForceRelogin(db.UserEng, ctx.GetInt("userid")); err != nil { + ctx.JSON(http.StatusOK, ErrMsg{Error: 1, Msg: "卡片添加成功,但登录状态刷新失败!"}) + return + } + ctx.JSON(http.StatusOK, ErrMsg{Error: 0, Msg: "导入成功,请重新打开游戏!"}) } diff --git a/internal/middleware/common.go b/internal/middleware/common.go index 7cade74..abe1ac0 100644 --- a/internal/middleware/common.go +++ b/internal/middleware/common.go @@ -11,16 +11,6 @@ import ( "github.com/gin-gonic/gin" ) -func CheckErr(ctx *gin.Context, err error) bool { - if err != nil { - ctx.AbortWithStatusJSON(http.StatusInternalServerError, gin.H{ - "code": 20001, - "message": err.Error(), - }) - } - return err != nil -} - func Common(ctx *gin.Context) { reqData := "" if form, err := ctx.MultipartForm(); err == nil { @@ -39,9 +29,17 @@ func Common(ctx *gin.Context) { ss := session.Attach(ctx) ctx.Set("session", ss) + if ctx.Request.URL.Path != "/login/authkey" && ctx.Request.URL.Path != "/login/login" { + if ss.UserPref.ForceRelogin { + ctx.AbortWithStatus(http.StatusNotFound) + return + } + } + authorize := ctx.GetHeader("Authorize") params, err := url.ParseQuery(authorize) - if CheckErr(ctx, err) { + if err != nil { + ctx.AbortWithStatus(http.StatusNotFound) return } diff --git a/internal/model/user/userpref.go b/internal/model/user/userpref.go index b9a0776..9378d3e 100644 --- a/internal/model/user/userpref.go +++ b/internal/model/user/userpref.go @@ -4,6 +4,8 @@ import ( "strconv" "strings" "time" + + "xorm.io/xorm" ) const CurrentUserPrefProfileVersion = 2 @@ -40,6 +42,7 @@ type UserPref struct { OverMaxEnergy int `xorm:"over_max_energy"` BirthMonth int `xorm:"birth_month"` BirthDay int `xorm:"birth_day"` + ForceRelogin bool `xorm:"force_relogin"` ProfileVersion int `xorm:"profile_version"` UpdateTime int64 `xorm:"update_time"` } @@ -154,10 +157,27 @@ func UserPrefProfileColumns() []string { "over_max_energy", "birth_month", "birth_day", + "force_relogin", "profile_version", } } +func MarkUserForceRelogin(exec xorm.Interface, userID int) error { + _, err := exec.Table(new(UserPref)). + Where("user_id = ?", userID). + Cols("force_relogin"). + Update(&UserPref{ForceRelogin: true}) + return err +} + +func ClearUserForceRelogin(exec xorm.Interface, userID int) error { + _, err := exec.Table(new(UserPref)). + Where("user_id = ?", userID). + Cols("force_relogin"). + Update(&UserPref{ForceRelogin: false}) + return err +} + func (UserPref) TableName() string { return "user_pref" }