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 <do4suki@gmail.com>
This commit is contained in:
2026-06-13 11:29:57 +08:00
parent 6264523c76
commit 4b2c005222
6 changed files with 74 additions and 11 deletions
+5
View File
@@ -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,
+19
View File
@@ -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: "删除成功,请重新登录游戏生效!",
+16
View File
@@ -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: "已恢复默认值!",
+5
View File
@@ -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: "导入成功,请重新打开游戏!"})
}
+9 -11
View File
@@ -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
}
+20
View File
@@ -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"
}