diff --git a/rc-service/rc-service-other/other-application/src/main/java/com/red/circle/other/app/command/activity/ClaimActivityRewardExe.java b/rc-service/rc-service-other/other-application/src/main/java/com/red/circle/other/app/command/activity/ClaimActivityRewardExe.java index d095786a..2656338d 100644 --- a/rc-service/rc-service-other/other-application/src/main/java/com/red/circle/other/app/command/activity/ClaimActivityRewardExe.java +++ b/rc-service/rc-service-other/other-application/src/main/java/com/red/circle/other/app/command/activity/ClaimActivityRewardExe.java @@ -9,8 +9,11 @@ import com.red.circle.other.app.dto.clientobject.activity.ClaimRewardResultCO; import com.red.circle.other.app.dto.cmd.activity.ClaimActivityRewardCmd; import com.red.circle.other.domain.gateway.props.ActivitySourceGroupGateway; import com.red.circle.other.infra.database.rds.dao.activity.UserActivityRewardClaimDAO; +import com.red.circle.other.infra.database.rds.entity.activity.LotteryDeviceRecord; import com.red.circle.other.infra.database.rds.entity.activity.UserActivityRewardClaim; +import com.red.circle.other.infra.database.rds.service.activity.LotteryDeviceRecordService; import com.red.circle.other.infra.database.rds.service.activity.UserActivityRechargeService; +import com.red.circle.other.infra.database.rds.service.user.device.LatestMobileDeviceService; import com.red.circle.other.inner.asserts.OtherErrorCode; import com.red.circle.other.inner.endpoint.activity.LotteryTicketClient; import com.red.circle.other.inner.enums.activity.PropsActivityTypeEnum; @@ -41,12 +44,17 @@ public class ClaimActivityRewardExe { private final UserActivityRechargeService userActivityRechargeService; private final UserActivityRewardClaimDAO userActivityRewardClaimDAO; private final LotteryTicketClient lotteryTicketClient; + private final LatestMobileDeviceService latestMobileDeviceService; + private final LotteryDeviceRecordService lotteryDeviceRecordService; @Transactional(rollbackFor = Exception.class) public ClaimRewardResultCO execute(ClaimActivityRewardCmd cmd) { PropsActivityTypeEnum activityType = PropsActivityTypeEnum.valueOf(cmd.getActivityType()); SysOriginPlatformEnum sysOrigin = SysOriginPlatformEnum.valueOf(cmd.getReqSysOrigin().getOrigin()); + // 2. 校验设备唯一性(防止小号薅羊毛) + checkDeviceUnique(cmd.getActivityId(), cmd.getReqUserId()); + List ruleConfigs = activitySourceGroupGateway.listRule(sysOrigin, activityType); ActivityPropsRule targetRule = ruleConfigs.stream() .filter(rule -> Objects.equals(rule.getId(), cmd.getRuleId())) @@ -108,6 +116,27 @@ public class ClaimActivityRewardExe { .setLotteryTicketIds(ticketIds); } + /** + * 校验设备唯一性(防止小号薅羊毛) + */ + private void checkDeviceUnique(Long activityId, Long userId) { + String fingerprint = latestMobileDeviceService.getEnhancedDeviceFingerprintByUserId(userId); + + if (com.red.circle.tool.core.text.StringUtils.isBlank(fingerprint)) { + log.warn("Failed to get device fingerprint, userId: {}", userId); + return; + } + + LotteryDeviceRecord existingRecord = lotteryDeviceRecordService + .getByActivityAndFingerprint(activityId, fingerprint); + + if (existingRecord != null && !existingRecord.getUserId().equals(userId)) { + log.warn("Duplicate device detected, activityId: {}, currentUser: {}, boundUser: {}, fingerprint: {}", + activityId, userId, existingRecord.getUserId(), fingerprint); + ResponseAssert.isTrue(OtherErrorCode.DEVICE_ALREADY_USED, false); + } + } + private BigDecimal parseRequiredAmount(String jsonData) { if (StrUtil.isBlank(jsonData)) { return null;