From b4c236d23446bb5014257f7c3b8143e663a1a1df Mon Sep 17 00:00:00 2001 From: XuqmGroup Date: Fri, 26 Jun 2026 13:42:48 +0800 Subject: [PATCH] =?UTF-8?q?fix(push):=20InternalPushController=20=E8=A1=A5?= =?UTF-8?q?=E4=BC=A0=20deviceId=EF=BC=9B=E8=AE=BE=E5=A4=87=E6=8D=A2?= =?UTF-8?q?=E7=BB=91=E6=97=B6=E9=A9=B1=E9=80=90=E5=8E=9F=E7=94=A8=E6=88=B7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - InternalPushController.testOffline 补传 deviceId=null,修复编译失败 - DeviceTokenRepository 新增 findByAppKeyAndDeviceId / findByAppKeyAndToken - registerToken 在同 appKey 下同设备/同 token 被新用户注册时, 自动删除旧用户的 push token,防止旧用户继续收到新用户的消息 Co-Authored-By: Claude Sonnet 4.6 --- .../push/controller/InternalPushController.java | 1 + .../push/repository/DeviceTokenRepository.java | 4 ++++ .../com/xuqm/push/service/PushDispatcher.java | 17 +++++++++++++++++ 3 files changed, 22 insertions(+) diff --git a/push-service/src/main/java/com/xuqm/push/controller/InternalPushController.java b/push-service/src/main/java/com/xuqm/push/controller/InternalPushController.java index 2bb360f..c68f075 100644 --- a/push-service/src/main/java/com/xuqm/push/controller/InternalPushController.java +++ b/push-service/src/main/java/com/xuqm/push/controller/InternalPushController.java @@ -96,6 +96,7 @@ public class InternalPushController { PushDiagnosticsService.TestPushResult result = diagnosticsService.sendTestOfflineMessage( request.appKey(), request.userId(), + null, request.title(), request.body(), request.payload()); diff --git a/push-service/src/main/java/com/xuqm/push/repository/DeviceTokenRepository.java b/push-service/src/main/java/com/xuqm/push/repository/DeviceTokenRepository.java index d4f5ecc..898f4a6 100644 --- a/push-service/src/main/java/com/xuqm/push/repository/DeviceTokenRepository.java +++ b/push-service/src/main/java/com/xuqm/push/repository/DeviceTokenRepository.java @@ -19,4 +19,8 @@ public interface DeviceTokenRepository extends JpaRepository findByAppKeyAndUserIdOrderByLastLoginAtDescUpdatedAtDesc(String appKey, String userId); void deleteByAppKeyAndUserIdAndVendor(String appKey, String userId, DeviceTokenEntity.Vendor vendor); void deleteByAppKeyAndUserIdAndDeviceId(String appKey, String userId, String deviceId); + // Find device by appKey+deviceId regardless of userId (for cross-user eviction) + Optional findByAppKeyAndDeviceId(String appKey, String deviceId); + // Find device by appKey+token regardless of userId (token rotation detection) + Optional findByAppKeyAndToken(String appKey, String token); } diff --git a/push-service/src/main/java/com/xuqm/push/service/PushDispatcher.java b/push-service/src/main/java/com/xuqm/push/service/PushDispatcher.java index 50463d4..bb15aa9 100644 --- a/push-service/src/main/java/com/xuqm/push/service/PushDispatcher.java +++ b/push-service/src/main/java/com/xuqm/push/service/PushDispatcher.java @@ -246,6 +246,23 @@ public class PushDispatcher { String appVersion, String romVersion) { String resolvedDeviceId = normalizeDeviceId(deviceId, vendor, token); + + // Evict previous owner: if this device (by deviceId OR token) is registered to another user, remove it + tokenRepository.findByAppKeyAndDeviceId(appKey, resolvedDeviceId) + .filter(prev -> !userId.equals(prev.getUserId())) + .ifPresent(prev -> { + log.info("Device {} re-registered by new user={}, evicting previous user={}", resolvedDeviceId, userId, prev.getUserId()); + recordLog(prev, DeviceLoginLogEntity.EventType.UNREGISTER); + tokenRepository.delete(prev); + }); + tokenRepository.findByAppKeyAndToken(appKey, token) + .filter(prev -> !userId.equals(prev.getUserId())) + .ifPresent(prev -> { + log.info("Token re-registered by new user={}, evicting previous user={} deviceId={}", userId, prev.getUserId(), prev.getDeviceId()); + recordLog(prev, DeviceLoginLogEntity.EventType.UNREGISTER); + tokenRepository.delete(prev); + }); + Optional existing = tokenRepository.findByAppKeyAndUserIdAndDeviceId(appKey, userId, resolvedDeviceId); if (existing.isEmpty() && (deviceId == null || deviceId.isBlank())) { existing = tokenRepository.findByAppKeyAndUserIdAndVendor(appKey, userId, vendor);