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);