From 038e5b6ab5df9bd79e74d86f54655b5169b93aae Mon Sep 17 00:00:00 2001 From: wangjia <809946525@qq.com> Date: Thu, 2 Jul 2026 01:54:53 +0800 Subject: [PATCH] =?UTF-8?q?fix(server):=20=E8=A2=AB=E7=A7=BB=E9=99=A4?= =?UTF-8?q?=E7=9A=84=E8=AE=BE=E5=A4=87=E4=BC=9A=E8=AF=9D=E8=BD=AE=E8=AF=A2?= =?UTF-8?q?=E5=88=A4=E6=B4=BB=20=E2=80=94=E2=80=94=20dev=20=E8=A1=8C?= =?UTF-8?q?=E4=B8=8D=E5=AD=98=E5=9C=A8=E5=BA=94=E5=88=A4=E3=80=8C=E5=A4=B1?= =?UTF-8?q?=E6=95=88=E3=80=8D=E8=80=8C=E9=9D=9E=E3=80=8C=E6=9C=89=E6=95=88?= =?UTF-8?q?=E3=80=8D(bug)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit SessionActive 在设备被 DeleteDevice 删行后 FindByUUID 返回 nil,此前一律 return true (「未知/非本人设备不据此登出」)。结果:被移除的设备轮询 /me/session 永远拿到 active=true → 不登出、不弹框,只表现为数据面凭证被召回→隧道断→客户端误报「节点异常」。 改为:dev==nil(自身 device_id 查无此行,已登录客户端必然注册过 → 只能是被移除)→ return false,让其登出;dev.UserID!=userID(他人 uuid)仍 return true 兜底。 Co-Authored-By: Claude Opus 4.8 --- server/internal/devices/service.go | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/server/internal/devices/service.go b/server/internal/devices/service.go index 0927a86..eb01bf7 100644 --- a/server/internal/devices/service.go +++ b/server/internal/devices/service.go @@ -382,8 +382,14 @@ func (svc *Service) SessionActive(ctx context.Context, userID int64, deviceUUID if err != nil { return false, apierr.ErrInternal } - if dev == nil || dev.UserID != userID { - return true, nil // 未知 / 非本人设备:不据此登出 + if dev == nil { + // 设备行已不存在 = 本设备被「移除」(DeleteDevice 删行)。已登录的客户端在登录时 + // 必然注册过自己的设备,轮询自身 device_id 却查无此行,只能是被移除 → 视为会话失效, + // 让其登出(否则被移除的设备永远收到 active=true,不退出,只表现为数据面被断→「节点异常」)。 + return false, nil + } + if dev.UserID != userID { + return true, nil // 非本人设备 uuid:不据此登出(fail-safe) } active, err := svc.sessions.HasActiveSession(ctx, userID, dev.ID) if err != nil {