新增 成为i主播设备校验

This commit is contained in:
tianfeng 2025-11-11 09:55:23 +08:00
parent 93014b56b7
commit a7eb054c03
10 changed files with 182 additions and 0 deletions

View File

@ -148,4 +148,13 @@ public interface RegisterDeviceClientApi {
*/
@GetMapping("/user/device/fingerprint")
ResultResponse<String> getDeviceFingerprintByUserId(@RequestParam("userId") Long userId);
/**
* 检查当前用户的设备指纹是否与其他主播用户共享
*
* @param userId 用户ID
* @return true-存在共享设备的主播用户, false-不存在
*/
@GetMapping("/user/device/fingerprint/check-anchor")
ResultResponse<Boolean> checkDeviceFingerprintHasAnchor(@RequestParam("userId") Long userId);
}

View File

@ -227,6 +227,11 @@ public enum TeamErrorCode implements IResponseErrorCode {
* 用户不是BD Leader
*/
USER_NOT_BDLEADER(6052, "User is not BD Leader"),
/**
* 设备指纹已被其他主播使用
*/
DEVICE_FINGERPRINT_USED_BY_ANCHOR(6053, "This device is already being used by another anchor"),
;
private final Integer code;

View File

@ -21,4 +21,20 @@ public interface RegisterDeviceGateway {
* @return true 允许注册false 不允许
*/
boolean checkAllowDeviceRegister(AllowDeviceRegisterCmd cmd);
/**
* 获取用户设备指纹
*
* @param userId 用户ID
* @return 设备指纹字符串
*/
String getDeviceFingerprintByUserId(Long userId);
/**
* 检查当前用户的设备指纹是否与其他主播用户共享
*
* @param userId 用户ID
* @return true-存在共享设备的主播用户, false-不存在
*/
Boolean checkDeviceFingerprintHasAnchor(Long userId);
}

View File

@ -3,6 +3,7 @@ package com.red.circle.other.infra.common.team.decay;
import com.red.circle.framework.core.asserts.ResponseAssert;
import com.red.circle.framework.core.response.CommonErrorCode;
import com.red.circle.other.domain.gateway.user.UserProfileGateway;
import com.red.circle.other.domain.gateway.user.ability.RegisterDeviceGateway;
import com.red.circle.other.domain.model.user.UserProfile;
import com.red.circle.other.infra.database.mongo.entity.team.team.TeamApplicationProcessApproval;
import com.red.circle.other.infra.database.mongo.entity.team.team.TeamMember;
@ -38,6 +39,7 @@ public class TeamMemberAddDecay {
private final TeamProfileService teamProfileService;
private final UserHistoryIdentityService historyIdentityService;
private final TeamApplicationProcessApprovalService applicationProcessApprovalService;
private final RegisterDeviceGateway registerDeviceGateway;
/**
* 添加成员.
@ -53,6 +55,11 @@ public class TeamMemberAddDecay {
ResponseAssert.isTrue(CommonErrorCode.OPERATION_CONFLICT,
Objects.equals(memberUser.getOriginSys(), teamProfile.getSysOrigin()));
// 主播设备指纹校验
Boolean hasAnchorWithSameDevice = registerDeviceGateway.checkDeviceFingerprintHasAnchor(
param.getMemberUserId());
ResponseAssert.isFalse(TeamErrorCode.DEVICE_FINGERPRINT_USED_BY_ANCHOR, hasAnchorWithSameDevice);
teamMemberService.addMember(new TeamMember()
.setSortId(IdWorkerUtils.getId())
.setSysOrigin(teamProfile.getSysOrigin())

View File

@ -116,4 +116,13 @@ public interface LatestMobileDeviceService extends BaseService<LatestMobileDevic
*/
String getDeviceFingerprintByUserId(Long userId);
/**
* 根据设备指纹获取所有使用该指纹的用户ID列表
*
* @param fingerprint 设备指纹
* @param sysOrigin 系统来源
* @return 用户ID列表
*/
List<Long> listUserIdsByDeviceFingerprint(String fingerprint, String sysOrigin);
}

View File

@ -311,4 +311,34 @@ public class LatestMobileDeviceServiceImpl extends
return requestClient + "|" + phoneModel + "|" + ip;
}
@Override
public List<Long> listUserIdsByDeviceFingerprint(String fingerprint, String sysOrigin) {
if (StringUtils.isBlank(fingerprint) || StringUtils.isBlank(sysOrigin)) {
return CollectionUtils.newArrayList();
}
String[] parts = fingerprint.split("\\|");
if (parts.length != 3) {
return CollectionUtils.newArrayList();
}
String requestClient = parts[0];
String phoneModel = parts[1];
String ip = parts[2];
return Optional.ofNullable(query()
.select(LatestMobileDevice::getUserId)
.eq(LatestMobileDevice::getRequestClient, requestClient)
.eq(LatestMobileDevice::getPhoneModel, phoneModel)
.eq(LatestMobileDevice::getIp, ip)
.eq(LatestMobileDevice::getSysOrigin, sysOrigin)
.last(PageConstant.formatLimit(500))
.list())
.map(devices -> devices.stream()
.map(LatestMobileDevice::getUserId)
.distinct()
.collect(Collectors.toList()))
.orElseGet(CollectionUtils::newArrayList);
}
}

View File

@ -1,5 +1,9 @@
package com.red.circle.other.infra.gateway.user;
import com.red.circle.other.domain.gateway.user.UserProfileGateway;
import com.red.circle.other.infra.database.mongo.entity.team.team.TeamMember;
import com.red.circle.other.infra.database.mongo.service.team.team.TeamMemberService;
import com.red.circle.other.infra.database.rds.service.user.device.LatestMobileDeviceService;
import com.red.circle.tool.core.text.StringUtils;
import com.red.circle.tool.core.thread.ThreadPoolManager;
import com.red.circle.other.domain.gateway.user.ability.RegisterDeviceGateway;
@ -21,6 +25,9 @@ public class RegisterDeviceGatewayImpl implements RegisterDeviceGateway {
private final IpRegisterQuantityService ipRegisterQuantityService;
private final DeviceRegisterQuantityService deviceRegisterQuantityService;
private final LatestMobileDeviceService latestMobileDeviceService;
private final UserProfileGateway userProfileGateway;
private final TeamMemberService teamMemberService;
/**
* 累计注册数量.
@ -66,4 +73,48 @@ public class RegisterDeviceGatewayImpl implements RegisterDeviceGateway {
>= cmd.getDeviceLimit();
}
@Override
public String getDeviceFingerprintByUserId(Long userId) {
return latestMobileDeviceService.getDeviceFingerprintByUserId(userId);
}
@Override
public Boolean checkDeviceFingerprintHasAnchor(Long userId) {
if (userId == null) {
return false;
}
com.red.circle.other.domain.model.user.UserProfile userProfile = userProfileGateway.getByUserId(userId);
if (userProfile == null) {
return false;
}
String fingerprint = latestMobileDeviceService.getDeviceFingerprintByUserId(userId);
if (StringUtils.isBlank(fingerprint)) {
return false;
}
java.util.List<Long> userIds = latestMobileDeviceService.listUserIdsByDeviceFingerprint(
fingerprint, userProfile.getOriginSys());
if (userIds == null || userIds.isEmpty()) {
return false;
}
for (Long otherUserId : userIds) {
if (java.util.Objects.equals(otherUserId, userId)) {
continue;
}
// 判断是否为主播检查用户是否为团队成员
TeamMember teamMember =
teamMemberService.getByMemberId(otherUserId);
if (teamMember != null) {
return true;
}
}
return false;
}
}

View File

@ -123,4 +123,9 @@ public class RegisterDeviceClientEndpoint implements RegisterDeviceClientApi {
public ResultResponse<String> getDeviceFingerprintByUserId(Long userId) {
return ResultResponse.success(registerDeviceClientService.getDeviceFingerprintByUserId(userId));
}
@Override
public ResultResponse<Boolean> checkDeviceFingerprintHasAnchor(Long userId) {
return ResultResponse.success(registerDeviceClientService.checkDeviceFingerprintHasAnchor(userId));
}
}

View File

@ -116,4 +116,12 @@ public interface RegisterDeviceClientService {
* @return 设备指纹字符串
*/
String getDeviceFingerprintByUserId(Long userId);
/**
* 检查当前用户的设备指纹是否与其他主播用户共享
*
* @param userId 用户ID
* @return true-存在共享设备的主播用户, false-不存在
*/
Boolean checkDeviceFingerprintHasAnchor(Long userId);
}

View File

@ -8,6 +8,8 @@ import com.red.circle.other.app.inner.convertor.user.UserProfileInnerConvertor;
import com.red.circle.other.app.inner.service.user.device.RegisterDeviceClientService;
import com.red.circle.other.domain.gateway.user.UserProfileGateway;
import com.red.circle.other.domain.model.user.UserProfile;
import com.red.circle.other.infra.database.mongo.entity.team.team.TeamMember;
import com.red.circle.other.infra.database.mongo.service.team.team.TeamMemberService;
import com.red.circle.other.infra.database.rds.entity.user.user.LatestMobileDevice;
import com.red.circle.other.infra.database.rds.service.user.device.ArchiveDeviceService;
import com.red.circle.other.infra.database.rds.service.user.device.DeviceRegisterQuantityService;
@ -49,6 +51,7 @@ public class RegisterDeviceClientServiceImpl implements RegisterDeviceClientServ
private final LatestMobileDeviceService latestMobileDeviceService;
private final RegisterDeviceInnerConvertor registerDeviceInnerConvertor;
private final DeviceRegisterQuantityService deviceRegisterQuantityService;
private final TeamMemberService teamMemberService;
@Override
public Boolean existsDevice(String deviceNo, String sysOrigin) {
@ -234,4 +237,43 @@ public class RegisterDeviceClientServiceImpl implements RegisterDeviceClientServ
public String getDeviceFingerprintByUserId(Long userId) {
return latestMobileDeviceService.getDeviceFingerprintByUserId(userId);
}
@Override
public Boolean checkDeviceFingerprintHasAnchor(Long userId) {
if (userId == null) {
return false;
}
UserProfile userProfile = userProfileGateway.getByUserId(userId);
if (userProfile == null) {
return false;
}
String fingerprint = latestMobileDeviceService.getDeviceFingerprintByUserId(userId);
if (StringUtils.isBlank(fingerprint)) {
return false;
}
List<Long> userIds = latestMobileDeviceService.listUserIdsByDeviceFingerprint(
fingerprint, userProfile.getOriginSys());
if (CollectionUtils.isEmpty(userIds)) {
return false;
}
for (Long otherUserId : userIds) {
if (Objects.equals(otherUserId, userId)) {
continue;
}
// 判断是否为主播检查用户是否为团队成员
TeamMember teamMember =
teamMemberService.getByMemberId(otherUserId);
if (teamMember != null) {
return true;
}
}
return false;
}
}