From 8f5ef2b9f434e28d5265c7d1f0f81108f2d1cb17 Mon Sep 17 00:00:00 2001 From: tianfeng <769204422@qq.com> Date: Wed, 31 Dec 2025 14:33:24 +0800 Subject: [PATCH] =?UTF-8?q?=E9=A2=86=E5=8F=96=E5=A5=96=E5=8A=B1=E5=A2=9E?= =?UTF-8?q?=E5=8A=A0=E8=AE=BE=E5=A4=87=E6=8C=87=E7=BA=B9=E6=A0=A1=E9=AA=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../activity/ClaimActivityRewardExe.java | 29 +++++++++++++++++++ 1 file changed, 29 insertions(+) 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;