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 <noreply@anthropic.com>
This commit is contained in:
2026-05-28 18:20:33 +08:00
parent ab3f188c04
commit 008e66f84e
+20 -26
View File
@@ -51,6 +51,12 @@ func handleAppLogout(c *gin.Context) {
return return
} }
// 只有 device_id 没有 instance_id 时提示错误
if req.DeviceID != "" && req.InstanceID == "" {
response.Error(c, 400, "缺少 instance_id 参数")
return
}
// 获取用户在该应用下的所有设备 // 获取用户在该应用下的所有设备
var devices []model.UserDevice var devices []model.UserDevice
if err := database.DB.Where("user_id = ? AND application_id = ?", userID, app.ID).Find(&devices).Error; err != nil { 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)) deviceIDs := make([]uint, len(devices))
deviceMap := make(map[uint]string)
for i, d := range devices { for i, d := range devices {
deviceIDs[i] = d.ID deviceIDs[i] = d.ID
deviceMap[d.ID] = d.DeviceID
} }
var deletedCount int64 var deletedCount int64
if req.DeviceID != "" { if req.InstanceID != "" && req.DeviceID != "" {
// 找到指定设备 // 清除指定设备的指定实例
var targetDeviceID uint var targetDeviceID uint
for _, d := range devices { for _, d := range devices {
if d.DeviceID == req.DeviceID { if d.DeviceID == req.DeviceID {
@@ -87,29 +91,19 @@ func handleAppLogout(c *gin.Context) {
return return
} }
if req.InstanceID != "" { result := database.DB.Where("device_id = ? AND instance_id = ?", targetDeviceID, req.InstanceID).Delete(&model.DeviceSession{})
// 清除指定实例 deletedCount = result.RowsAffected
result := database.DB.Where("device_id = ? AND instance_id = ?", targetDeviceID, req.InstanceID).Delete(&model.DeviceSession{}) log.Printf("[INFO] Logout: deleted session for device %s, instance %s, count %d", req.DeviceID, req.InstanceID, deletedCount)
deletedCount = result.RowsAffected } else if req.InstanceID != "" {
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 IN ? AND instance_id = ?", deviceIDs, req.InstanceID).Delete(&model.DeviceSession{})
// 清除该设备所有实例 deletedCount = result.RowsAffected
result := database.DB.Where("device_id = ?", targetDeviceID).Delete(&model.DeviceSession{}) log.Printf("[INFO] Logout: deleted instance %s across all devices, count %d", req.InstanceID, deletedCount)
deletedCount = result.RowsAffected
log.Printf("[INFO] Logout: deleted all sessions for device %s, count %d", req.DeviceID, deletedCount)
}
} else { } else {
if req.InstanceID != "" { // 清除该用户所有实例
// 清除指定实例(跨设备) result := database.DB.Where("device_id IN ?", deviceIDs).Delete(&model.DeviceSession{})
result := database.DB.Where("device_id IN ? AND instance_id = ?", deviceIDs, req.InstanceID).Delete(&model.DeviceSession{}) deletedCount = result.RowsAffected
deletedCount = result.RowsAffected log.Printf("[INFO] Logout: deleted all sessions for user %d, count %d", userID, deletedCount)
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)
}
} }
service.LogVerification(c, &app.ID, uintPtr(userID.(uint)), "logout", fmt.Sprintf("用户登出,清除 %d 个实例", deletedCount), req.DeviceID, nil) service.LogVerification(c, &app.ID, uintPtr(userID.(uint)), "logout", fmt.Sprintf("用户登出,清除 %d 个实例", deletedCount), req.DeviceID, nil)