diff --git a/rc-service/rc-service-other/other-application/src/main/java/com/red/circle/other/app/command/task/CheckInExe.java b/rc-service/rc-service-other/other-application/src/main/java/com/red/circle/other/app/command/task/CheckInExe.java index 6884b244..056bf4a3 100644 --- a/rc-service/rc-service-other/other-application/src/main/java/com/red/circle/other/app/command/task/CheckInExe.java +++ b/rc-service/rc-service-other/other-application/src/main/java/com/red/circle/other/app/command/task/CheckInExe.java @@ -6,6 +6,7 @@ import com.red.circle.component.redis.service.RedisService; import com.red.circle.framework.core.asserts.ResponseAssert; import com.red.circle.framework.core.response.CommonErrorCode; import com.red.circle.other.app.dto.cmd.task.CheckInRewardCmd; +import com.red.circle.other.app.util.EnhancedDeviceUtil; import com.red.circle.other.infra.common.activity.PropsActivitySendCommon; import com.red.circle.other.infra.common.props.PropsSendCommon; import com.red.circle.other.infra.database.cache.key.CheckInKeys; @@ -13,6 +14,7 @@ import com.red.circle.other.infra.database.cache.service.other.CheckInCacheServi import com.red.circle.other.infra.database.rds.entity.activity.LotteryDeviceRecord; import com.red.circle.other.infra.database.rds.entity.activity.PropsActivityRewardConfig; import com.red.circle.other.infra.database.rds.entity.activity.PropsActivityRuleConfig; +import com.red.circle.other.infra.database.rds.entity.user.user.LatestMobileDevice; import com.red.circle.other.infra.database.rds.service.activity.LotteryDeviceRecordService; import com.red.circle.other.infra.database.rds.service.activity.PropsActivityRewardConfigService; import com.red.circle.other.infra.database.rds.service.activity.PropsActivityRuleConfigService; @@ -126,8 +128,6 @@ public class CheckInExe { .setQuantity(config.getQuantity()))) ); - recordDeviceAfterDraw(AZIZI_FIXED_ACTIVITY_ID, cmd.getReqUserId()); - return checkInCacheService.getCheckInDays(sevenCheckInKey); } finally { @@ -139,31 +139,33 @@ public class CheckInExe { * 校验设备唯一性(防止小号薅羊毛) */ private void checkDeviceUnique(Long activityId, Long userId) { - String fingerprint = latestMobileDeviceService.getEnhancedDeviceFingerprintByUserId(userId); + LatestMobileDevice device = latestMobileDeviceService.getByUserId(userId); - if (StringUtils.isBlank(fingerprint)) { + if (device == null) { return; } - LotteryDeviceRecord existingRecord = lotteryDeviceRecordService - .getByActivityAndFingerprint(activityId, fingerprint); + // 1. 先用新指纹查询(不含IMEI) + String fingerprintV2 = EnhancedDeviceUtil.buildEnhancedDeviceFingerprintV2(device); + LotteryDeviceRecord existingRecord = lotteryDeviceRecordService.getByActivityAndFingerprint(activityId, fingerprintV2); if (existingRecord != null && !existingRecord.getUserId().equals(userId)) { ResponseAssert.isTrue(OtherErrorCode.DEVICE_ALREADY_USED, false); } - } - /** - * 记录设备信息 - */ - private void recordDeviceAfterDraw(Long activityId, Long userId) { - try { - String fingerprint = latestMobileDeviceService.getEnhancedDeviceFingerprintByUserId(userId); - if (StringUtils.isNotBlank(fingerprint)) { - lotteryDeviceRecordService.recordDevice(activityId, userId, fingerprint); + // 2. 兜底:再用旧指纹查询(含IMEI)- 兼容历史数据 + String fingerprintV1 = EnhancedDeviceUtil.buildEnhancedDeviceFingerprint(device); + if (!fingerprintV1.equals(fingerprintV2)) { // 只有当两个指纹不同时才需要再查一次 + LotteryDeviceRecord existingRecordV1 = lotteryDeviceRecordService + .getByActivityAndFingerprint(activityId, fingerprintV1); + + if (existingRecordV1 != null && !existingRecordV1.getUserId().equals(userId)) { + ResponseAssert.isTrue(OtherErrorCode.DEVICE_ALREADY_USED, false); } - } catch (Exception e) { } + + lotteryDeviceRecordService.recordDevice(activityId, userId, fingerprintV2); + } /** diff --git a/rc-service/rc-service-other/other-application/src/main/java/com/red/circle/other/app/util/EnhancedDeviceUtil.java b/rc-service/rc-service-other/other-application/src/main/java/com/red/circle/other/app/util/EnhancedDeviceUtil.java new file mode 100644 index 00000000..e0ff28ab --- /dev/null +++ b/rc-service/rc-service-other/other-application/src/main/java/com/red/circle/other/app/util/EnhancedDeviceUtil.java @@ -0,0 +1,67 @@ +package com.red.circle.other.app.util; + +import com.alibaba.nacos.common.utils.StringUtils; +import com.red.circle.other.infra.database.rds.entity.user.user.LatestMobileDevice; + +import java.util.Objects; + +public class EnhancedDeviceUtil { + + /** + * 构建增强版设备指纹(新版本 - 不含IMEI) + * 组成:手机型号 + 系统版本 + IP段 + 编译版本 + */ + public static String buildEnhancedDeviceFingerprintV2(LatestMobileDevice device) { + StringBuilder sb = new StringBuilder(); + + sb.append(StringUtils.isBlank(device.getPhoneModel()) ? "" : device.getPhoneModel()).append("|"); + sb.append(StringUtils.isBlank(device.getPhoneSysVersion()) ? "" : device.getPhoneSysVersion()).append("|"); + sb.append(getIpPrefix(device.getIp())).append("|"); + sb.append(Objects.nonNull(device.getBuildVersion()) ? device.getBuildVersion() : 0); + + return sb.toString(); + } + + /** + * 构建增强版设备指纹 + * 组成:手机型号 + 系统版本 + IMEI + IP段 + 编译版本 + */ + public static String buildEnhancedDeviceFingerprint(LatestMobileDevice device) { + StringBuilder sb = new StringBuilder(); + + sb.append(com.red.circle.tool.core.text.StringUtils.isBlank(device.getPhoneModel()) ? "" : device.getPhoneModel()).append("|"); + sb.append(com.red.circle.tool.core.text.StringUtils.isBlank(device.getPhoneSysVersion()) ? "" : device.getPhoneSysVersion()).append("|"); + sb.append(com.red.circle.tool.core.text.StringUtils.isBlank(device.getImei()) ? "" : device.getImei()).append("|"); + sb.append(getIpPrefix(device.getIp())).append("|"); + sb.append(Objects.nonNull(device.getBuildVersion()) ? device.getBuildVersion() : 0); + + return sb.toString(); + } + + /** + * 获取IP前缀段(提高稳定性) + * IPv4: 取前3段(如 192.168.1.xxx -> 192.168.1) + * IPv6: 取前4段(如 2a0d:5600:24:449:xxx -> 2a0d:5600:24:449) + */ + private static String getIpPrefix(String ip) { + if (com.red.circle.tool.core.text.StringUtils.isBlank(ip)) { + return ""; + } + + if (ip.contains(":")) { + String[] parts = ip.split(":"); + if (parts.length >= 4) { + return parts[0] + ":" + parts[1] + ":" + parts[2] + ":" + parts[3]; + } + return ip; + } else { + String[] parts = ip.split("\\."); + if (parts.length >= 3) { + return parts[0] + "." + parts[1] + "." + parts[2]; + } + return ip; + } + } + + +}