From 008e66f84e50a1b3c5d1ef488ab8afedd2238f24 Mon Sep 17 00:00:00 2001 From: admin Date: Thu, 28 May 2026 18:20:33 +0800 Subject: [PATCH] fix: require instance_id when device_id is provided on logout - Only device_id without instance_id returns error - Three valid combinations: - device_id + instance_id: clear specific instance - only instance_id: clear instance across devices - no params: clear all instances Co-Authored-By: Claude Opus 4.7 --- backend/internal/router/app/user.go | 46 +++++++++++++---------------- 1 file changed, 20 insertions(+), 26 deletions(-) diff --git a/backend/internal/router/app/user.go b/backend/internal/router/app/user.go index e93e3fa..8688117 100644 --- a/backend/internal/router/app/user.go +++ b/backend/internal/router/app/user.go @@ -51,6 +51,12 @@ func handleAppLogout(c *gin.Context) { return } + // 只有 device_id 没有 instance_id 时提示错误 + if req.DeviceID != "" && req.InstanceID == "" { + response.Error(c, 400, "缺少 instance_id 参数") + return + } + // 获取用户在该应用下的所有设备 var devices []model.UserDevice if err := database.DB.Where("user_id = ? AND application_id = ?", userID, app.ID).Find(&devices).Error; err != nil { @@ -64,16 +70,14 @@ func handleAppLogout(c *gin.Context) { } deviceIDs := make([]uint, len(devices)) - deviceMap := make(map[uint]string) for i, d := range devices { deviceIDs[i] = d.ID - deviceMap[d.ID] = d.DeviceID } var deletedCount int64 - if req.DeviceID != "" { - // 找到指定的设备 + if req.InstanceID != "" && req.DeviceID != "" { + // 清除指定设备的指定实例 var targetDeviceID uint for _, d := range devices { if d.DeviceID == req.DeviceID { @@ -87,29 +91,19 @@ func handleAppLogout(c *gin.Context) { return } - if req.InstanceID != "" { - // 清除指定实例 - result := database.DB.Where("device_id = ? AND instance_id = ?", targetDeviceID, req.InstanceID).Delete(&model.DeviceSession{}) - deletedCount = result.RowsAffected - log.Printf("[INFO] Logout: deleted session for device %s, instance %s, count %d", req.DeviceID, req.InstanceID, deletedCount) - } else { - // 清除该设备所有实例 - result := database.DB.Where("device_id = ?", targetDeviceID).Delete(&model.DeviceSession{}) - deletedCount = result.RowsAffected - log.Printf("[INFO] Logout: deleted all sessions for device %s, count %d", req.DeviceID, deletedCount) - } + result := database.DB.Where("device_id = ? AND instance_id = ?", targetDeviceID, req.InstanceID).Delete(&model.DeviceSession{}) + deletedCount = result.RowsAffected + log.Printf("[INFO] Logout: deleted session for device %s, instance %s, count %d", req.DeviceID, req.InstanceID, deletedCount) + } else if req.InstanceID != "" { + // 清除指定实例(跨设备) + result := database.DB.Where("device_id IN ? AND instance_id = ?", deviceIDs, req.InstanceID).Delete(&model.DeviceSession{}) + deletedCount = result.RowsAffected + log.Printf("[INFO] Logout: deleted instance %s across all devices, count %d", req.InstanceID, deletedCount) } else { - if req.InstanceID != "" { - // 清除指定实例(跨设备) - result := database.DB.Where("device_id IN ? AND instance_id = ?", deviceIDs, req.InstanceID).Delete(&model.DeviceSession{}) - deletedCount = result.RowsAffected - log.Printf("[INFO] Logout: deleted instance %s across all devices, count %d", req.InstanceID, deletedCount) - } else { - // 清除该用户所有实例 - result := database.DB.Where("device_id IN ?", deviceIDs).Delete(&model.DeviceSession{}) - deletedCount = result.RowsAffected - log.Printf("[INFO] Logout: deleted all sessions for user %d, count %d", userID, deletedCount) - } + // 清除该用户所有实例 + result := database.DB.Where("device_id IN ?", deviceIDs).Delete(&model.DeviceSession{}) + deletedCount = result.RowsAffected + log.Printf("[INFO] Logout: deleted all sessions for user %d, count %d", userID, deletedCount) } service.LogVerification(c, &app.ID, uintPtr(userID.(uint)), "logout", fmt.Sprintf("用户登出,清除 %d 个实例", deletedCount), req.DeviceID, nil)