fix(backend): 改为后台配置注册限流阈值

This commit is contained in:
Zhou Weidong committed 2026-10-17 23:29:25 +08:00
1 parent 78fb99530d
commit f1aaaee814
8 files changed
+79 -39

No files matched your search

@@ -6,6 +6,7 @@ import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.fruitshorts.common.exception.ErrorCode;
import com.fruitshorts.common.exception.ServiceException;
import com.fruitshorts.framework.security.JwtTokenProvider;
import com.fruitshorts.system.service.ConfigService;
import com.fruitshorts.user.dal.entity.AppUser;
import com.fruitshorts.user.dal.entity.AppUserConsent;
import com.fruitshorts.user.dal.entity.AppUserCredential;
@@ -25,7 +26,6 @@ import com.fruitshorts.user.vo.LogoutReqVO;
import com.fruitshorts.user.vo.RegisterReqVO;
import com.fruitshorts.user.vo.TokenRespVO;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.dao.DuplicateKeyException;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
@@ -59,6 +59,7 @@ public class AppAuthService {
private final CredentialHasher hasher;
private final JwtTokenProvider tokenProvider;
private final PasswordEncoder passwordEncoder;
private final ConfigService configService;
@Transactional(rollbackFor = Exception.class)
public TokenRespVO register(RegisterReqVO req, String clientIp) {
@@ -302,13 +303,10 @@ public class AppAuthService {
return resp;
}
/** 每个 IP 24 小时内最多注册几个账号;小于等于 0 表示不限制。 */
@Value("${fruitshorts.auth.register-max-per-ip-per-day:5}")
private int maxRegisterPerIpPerDay = 5;
/** 每台设备 24 小时内最多注册几个账号;小于等于 0 表示不限制。 */
@Value("${fruitshorts.auth.register-max-per-device-per-day:3}")
private int maxRegisterPerDevicePerDay = 3;
private static final String REGISTER_IP_LIMIT_KEY = "app.register.max-per-ip-per-day";
private static final String REGISTER_DEVICE_LIMIT_KEY = "app.register.max-per-device-per-day";
private static final int DEFAULT_REGISTER_IP_LIMIT = 5;
private static final int DEFAULT_REGISTER_DEVICE_LIMIT = 3;
private static final int PASSWORD_MIN_LENGTH = 8;
private static final int PASSWORD_MAX_LENGTH = 64;
@@ -341,26 +339,40 @@ public class AppAuthService {
*/
private void guardRegisterRisk(String clientIp, String deviceId) {
LocalDateTime since = LocalDateTime.now().minusDays(1);
int ipLimit = registerLimit(REGISTER_IP_LIMIT_KEY, DEFAULT_REGISTER_IP_LIMIT);
int deviceLimit = registerLimit(REGISTER_DEVICE_LIMIT_KEY, DEFAULT_REGISTER_DEVICE_LIMIT);
String ip = AppIdentifier.nullSafe(clientIp);
if (maxRegisterPerIpPerDay > 0 && StringUtils.hasText(ip)) {
if (ipLimit > 0 && StringUtils.hasText(ip)) {
Long byIp = appUserMapper.selectCount(Wrappers.<AppUser>lambdaQuery()
.eq(AppUser::getRegisterIp, ip)
.ge(AppUser::getCreatedAt, since));
if (byIp != null && byIp >= maxRegisterPerIpPerDay) {
if (byIp != null && byIp >= ipLimit) {
throw new ServiceException(ErrorCode.TOO_MANY_REQUESTS, "当前网络注册过于频繁,请稍后再试");
}
}
String device = AppIdentifier.nullSafe(deviceId);
if (maxRegisterPerDevicePerDay > 0 && StringUtils.hasText(device)) {
if (deviceLimit > 0 && StringUtils.hasText(device)) {
Long byDevice = appUserMapper.selectCount(Wrappers.<AppUser>lambdaQuery()
.eq(AppUser::getRegisterDeviceId, device)
.ge(AppUser::getCreatedAt, since));
if (byDevice != null && byDevice >= maxRegisterPerDevicePerDay) {
if (byDevice != null && byDevice >= deviceLimit) {
throw new ServiceException(ErrorCode.TOO_MANY_REQUESTS, "该设备注册过于频繁,请稍后再试");
}
}
}
private int registerLimit(String key, int defaultValue) {
String raw = configService.get(key, String.valueOf(defaultValue));
if (!StringUtils.hasText(raw)) {
return defaultValue;
}
try {
return Integer.parseInt(raw.trim());
} catch (NumberFormatException ex) {
return defaultValue;
}
}
private AppUser createUser(RegisterReqVO req, String clientIp) {
AppUser user = new AppUser();
user.setUid(hasher.newUid());