Compare commits

...

2 Commits

Author SHA1 Message Date
ZuoZuo
2a6599cd5a fix(other): allow avatar updates for country-locked users 2026-07-15 00:21:31 +08:00
ZuoZuo
1f2f8b0f6d fix(auth): temporarily bypass IP country check 2026-07-10 01:12:11 +08:00
3 changed files with 112 additions and 56 deletions

View File

@ -1,7 +1,5 @@
package com.red.circle.auth.endpoint;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.red.circle.auth.common.ProcessToken;
import com.red.circle.auth.dto.TokenCredentialCO;
import com.red.circle.auth.response.AuthErrorCode;
@ -32,12 +30,6 @@ import java.util.concurrent.TimeUnit;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
@ -68,9 +60,6 @@ public class EndpointRestController {
private final String LOGIN_WHITE_CONFIG = "LOGIN_WHITE_CONFIG";
private final String APPCODE_CONFIG = "APPCODE 35493154e8304e47943ca596706da44f";
private final String REQUEST_URL = "https://c2ba.api.huachen.cn/ip";
private final RedisService redisService;
/**
@ -283,45 +272,9 @@ public class EndpointRestController {
}
public String checkIpAddress(String ip) {
String redisKey = "IP_KEY:" + ip;
String data = redisService.getString(redisKey);
JSONObject dataObject = null;
if (StringUtils.isNotBlank(data)) {
dataObject = JSONObject.parseObject(data);
} else {
//每一个ip地址只能有一次校验
HttpGet httpGet = new HttpGet(REQUEST_URL + "?ip=" + ip);
httpGet.addHeader("Authorization", APPCODE_CONFIG);
RequestConfig requestConfig = RequestConfig.custom()
.setConnectTimeout(10000).setSocketTimeout(10000).setConnectionRequestTimeout(10000).build();
try (CloseableHttpClient httpClient = HttpClients.custom().setDefaultRequestConfig(requestConfig).build();
CloseableHttpResponse response = httpClient.execute(httpGet)) {
String result = EntityUtils.toString(response.getEntity());
log.info("请求地址:{},返回信息:{}", REQUEST_URL + "?ip=" + ip, result);
JSONObject jsonObject = JSON.parseObject(result);
if (jsonObject.getInteger("ret").equals(200)) {
dataObject = jsonObject.getJSONObject("data");
redisService.setString(redisKey, dataObject.toJSONString());
}
} catch (Exception e) {
log.error("请求地址:{}, 异常信息:{}", REQUEST_URL + "?ip=" + ip, e.getMessage());
}
}
log.info("IP:{}, 国家信息:{}", ip, dataObject);
// IP 归属接口超时或返回异常时不能让登录链路 NPE中港台拦截只在拿到明确国家信息时执行
if (dataObject == null) {
log.warn("IP:{} 国家信息获取失败,跳过 IP 国家校验", ip);
log.info("IP:{} 临时跳过 IP 国家校验", ip);
return null;
}
if (dataObject != null && "中国".equals(dataObject.getString("country"))) {
if (!Arrays.asList("香港", "澳门", "台湾").contains(dataObject.getString("region"))) {
ResponseAssert.isTrue(UserErrorCode.REGISTRATION_FAILED, false);
}
}
return dataObject.getString("country_id");
}
public void checkZone(String reqZone) {
log.info("reqZone:{}", reqZone);

View File

@ -134,25 +134,27 @@ public class UpdateUserProfileCmdExe {
return userProfileAppConvertor.toUserProfileDTO(userProfile);
}
private SysCountryCode getChangeCountry(UserProfileModifyCmd cmd, UserProfile userProfile) {
SysCountryCode getChangeCountry(UserProfileModifyCmd cmd, UserProfile userProfile) {
// App 保存资料可能会携带当前国家 id只拦截真实变更避免昵称头像等普通资料保存被误伤
if (Objects.isNull(cmd.getCountryId())
|| Objects.equals(userProfile.getCountryId(), cmd.getCountryId())) {
return null;
}
// 客户端保存头像等资料时会回传整份资料国家 id 可能来自 IP 定位或旧缓存
// 对国家锁定用户只忽略国家字段不能让它阻断头像昵称等无关资料更新
if (userIdentityService.hasCountryLockedIdentity(userProfile.getId())) {
log.warn("ignore country change from profile update userId={}, currentCountryId={}, requestCountryId={}",
userProfile.getId(), userProfile.getCountryId(), cmd.getCountryId());
return null;
}
Map<Long, SysCountryCode> countryMap = sysCountryCodeService.mapByIdes(Set.of(cmd.getCountryId()));
SysCountryCode country = countryMap.get(cmd.getCountryId());
ResponseAssert.notNull(UserErrorCode.SYS_REGION_NOT_EXIST_ERROR, country);
assertAllowCountryChange(userProfile.getId());
return country;
}
private void assertAllowCountryChange(Long userId) {
ResponseAssert.isFalse(UserErrorCode.USER_COUNTRY_UPDATE_NOT_ALLOWED,
userIdentityService.hasCountryLockedIdentity(userId));
}
private void syncRoomCountry(Long userId, SysCountryCode country) {
userProfileGateway.removeCacheAll(userId);
String regionCode = userRegionGateway.getRegionCode(userId);

View File

@ -0,0 +1,101 @@
package com.red.circle.other.app.command.user;
import static org.junit.jupiter.api.Assertions.assertNull;
import static org.junit.jupiter.api.Assertions.assertSame;
import static org.mockito.ArgumentMatchers.anySet;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import com.red.circle.external.inner.endpoint.oss.OssServiceClient;
import com.red.circle.other.app.convertor.user.UserProfileAppConvertor;
import com.red.circle.other.app.dto.cmd.user.user.UserProfileModifyCmd;
import com.red.circle.other.app.service.user.user.UserIdentityService;
import com.red.circle.other.domain.gateway.approval.ProfileApprovalGateway;
import com.red.circle.other.domain.gateway.user.UserProfileGateway;
import com.red.circle.other.domain.gateway.user.ability.UserRegionGateway;
import com.red.circle.other.domain.model.user.UserProfile;
import com.red.circle.other.infra.database.cache.service.cp.CpRelationshipCacheService;
import com.red.circle.other.infra.database.mongo.service.live.ActiveVoiceRoomService;
import com.red.circle.other.infra.database.mongo.service.live.RoomProfileManagerService;
import com.red.circle.other.infra.database.rds.entity.sys.SysCountryCode;
import com.red.circle.other.infra.database.rds.service.sys.SysCountryCodeService;
import java.util.Map;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
@ExtendWith(MockitoExtension.class)
class UpdateUserProfileCmdExeTest {
@Mock private OssServiceClient ossServiceClient;
@Mock private UserProfileGateway userProfileGateway;
@Mock private ProfileApprovalGateway profileApprovalGateway;
@Mock private UserProfileAppConvertor userProfileAppConvertor;
@Mock private CpRelationshipCacheService cpRelationshipCacheService;
@Mock private UserIdentityService userIdentityService;
@Mock private SysCountryCodeService sysCountryCodeService;
@Mock private RoomProfileManagerService roomProfileManagerService;
@Mock private ActiveVoiceRoomService activeVoiceRoomService;
@Mock private UserRegionGateway userRegionGateway;
private UpdateUserProfileCmdExe executor;
@BeforeEach
void setUp() {
executor = new UpdateUserProfileCmdExe(
ossServiceClient,
userProfileGateway,
profileApprovalGateway,
userProfileAppConvertor,
cpRelationshipCacheService,
userIdentityService,
sysCountryCodeService,
roomProfileManagerService,
activeVoiceRoomService,
userRegionGateway);
}
@Test
void shouldIgnoreDifferentCountryForLockedUserSoOtherProfileFieldsCanUpdate() {
UserProfile profile = profile(10L, 100L);
UserProfileModifyCmd cmd = new UserProfileModifyCmd().setCountryId(200L);
when(userIdentityService.hasCountryLockedIdentity(10L)).thenReturn(true);
assertNull(executor.getChangeCountry(cmd, profile));
verify(sysCountryCodeService, never()).mapByIdes(anySet());
}
@Test
void shouldResolveDifferentCountryForUnlockedUser() {
UserProfile profile = profile(10L, 100L);
UserProfileModifyCmd cmd = new UserProfileModifyCmd().setCountryId(200L);
SysCountryCode target = new SysCountryCode().setId(200L).setAlphaTwo("EG")
.setCountryName("Egypt");
when(userIdentityService.hasCountryLockedIdentity(10L)).thenReturn(false);
when(sysCountryCodeService.mapByIdes(anySet())).thenReturn(Map.of(200L, target));
assertSame(target, executor.getChangeCountry(cmd, profile));
}
@Test
void shouldSkipCountryChecksWhenRequestCarriesCurrentCountry() {
UserProfile profile = profile(10L, 100L);
UserProfileModifyCmd cmd = new UserProfileModifyCmd().setCountryId(100L);
assertNull(executor.getChangeCountry(cmd, profile));
verify(userIdentityService, never()).hasCountryLockedIdentity(10L);
verify(sysCountryCodeService, never()).mapByIdes(anySet());
}
private UserProfile profile(Long userId, Long countryId) {
UserProfile profile = new UserProfile();
profile.setId(userId);
profile.setCountryId(countryId);
return profile;
}
}