fix(push): InternalPushController 补传 deviceId;设备换绑时驱逐原用户
- InternalPushController.testOffline 补传 deviceId=null,修复编译失败 - DeviceTokenRepository 新增 findByAppKeyAndDeviceId / findByAppKeyAndToken - registerToken 在同 appKey 下同设备/同 token 被新用户注册时, 自动删除旧用户的 push token,防止旧用户继续收到新用户的消息 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
这个提交包含在:
父节点
68f6145c71
当前提交
b4c236d234
@ -96,6 +96,7 @@ public class InternalPushController {
|
||||
PushDiagnosticsService.TestPushResult result = diagnosticsService.sendTestOfflineMessage(
|
||||
request.appKey(),
|
||||
request.userId(),
|
||||
null,
|
||||
request.title(),
|
||||
request.body(),
|
||||
request.payload());
|
||||
|
||||
@ -19,4 +19,8 @@ public interface DeviceTokenRepository extends JpaRepository<DeviceTokenEntity,
|
||||
List<DeviceTokenEntity> 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<DeviceTokenEntity> findByAppKeyAndDeviceId(String appKey, String deviceId);
|
||||
// Find device by appKey+token regardless of userId (token rotation detection)
|
||||
Optional<DeviceTokenEntity> findByAppKeyAndToken(String appKey, String token);
|
||||
}
|
||||
|
||||
@ -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<DeviceTokenEntity> existing = tokenRepository.findByAppKeyAndUserIdAndDeviceId(appKey, userId, resolvedDeviceId);
|
||||
if (existing.isEmpty() && (deviceId == null || deviceId.isBlank())) {
|
||||
existing = tokenRepository.findByAppKeyAndUserIdAndVendor(appKey, userId, vendor);
|
||||
|
||||
正在加载...
在新工单中引用
屏蔽一个用户