Эх сурвалжийг харах

fix 修复小店登录爆破返回

zoujiajian 1 долоо хоног өмнө
parent
commit
15af8e772d

+ 45 - 43
netflix-service/src/main/java/com/cyksj/service/cps/shop/YhShopManageServiceImpl.java

@@ -26,6 +26,7 @@ import com.cyksj.service.mail.MailService;
 import com.cyksj.service.pay.TransferFuncService;
 import com.cyksj.service.user.BadIntentionOpService;
 import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
 import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
 
@@ -40,6 +41,7 @@ import java.util.Optional;
  *创建时间:2023/9/19 17:36
  */
 @Service
+@Slf4j
 @RequiredArgsConstructor
 public class YhShopManageServiceImpl implements YhShopManageService{
 	private final YhShopMapper yhShopMapper;
@@ -64,49 +66,49 @@ public class YhShopManageServiceImpl implements YhShopManageService{
 
 	@Override
 	public void getLoginCode(Integer type, String login, Integer cid, String verifyCode, String ticket, String randStr) {
-		if (type > 2) {
-			throw BusinessRuntimeException.getInstance("");
-		}
-		if (cid == null) {
-			cid = 86;
-		}
-		String phone = null;
-		String email = null;
-		if (type == 1) phone = login;
-		else if (type == 2) email = login;
-		User user = userMapper.selectOne(Wrappers.lambdaQuery(User.class)
-				.eq(StrUtil.isNotBlank(phone), User::getLoginPhone, phone)
-				.eq(StrUtil.isNotBlank(email), User::getEmail, email).last("limit 1"));
-		if (user == null) throw BusinessRuntimeException.getInstance("登录信息不存在");
-		//是否是店铺主
-		YhShop yhShop = yhShopMapper.selectOne(Wrappers.lambdaQuery(YhShop.class)
-				.eq(YhShop::getVerifyStatus, YhShop.Status.success)
-				.eq(YhShop::getUserId, user.getId()).last("limit 1"));
-		if (yhShop == null) {
-			throw BusinessRuntimeException.getInstance("您不是银河小店店铺主");
-		}
-
-		String CACHE_LOGIN_KEY = RedisService.key.YH_SHOP_BACK_LOGIN_KEY.getName()  + login;
-		Object o = redisService.get(CACHE_LOGIN_KEY);
-		Long expire = redisService.getExpire(CACHE_LOGIN_KEY);
-		if (o != null && expire >= 3 * 60 - 10) {
-			throw BusinessRuntimeException.getInstance("获取验证码过于频繁");
-		}
-		String code = StringUtil.getRandomCodeStr(6);
-		if (type == 1) {
-			if (StrUtil.isEmpty(login) || (86 == cid && !Validator.isMobile(phone))) {
-				throw BusinessRuntimeException.getInstance("请输入正确的手机号");
-			}
-			//是否是恶意用户
-			badIntentionOpService.checkHandleBadUserOp(phone, verifyCode, ticket, randStr, request);
-			SmsUtil.sendTencent(cid, login, code);
-		} else if (type == 2) {
-			if (!Validator.isEmail(login)) {
-				throw BusinessRuntimeException.getInstance("请输入正确的邮箱");
-			}
-			mailService.sendLoginCodeEmailToPeople(code, login);
-		}
-		redisService.set(CACHE_LOGIN_KEY, code, RedisService.key.YH_SHOP_BACK_LOGIN_KEY.getTimeout());
+        if (type == null || (type != 1 && type != 2)) {
+            throw BusinessRuntimeException.getInstance("不支持的登录方式");
+        }
+        if (cid == null) cid = 86;
+        if (StrUtil.isBlank(login) || login.length() > 254) {
+            throw BusinessRuntimeException.getInstance("请输入正确的登录账号");
+        }
+        if (type == 1 && (cid <= 0 || (cid == 86 && !Validator.isMobile(login)))) {
+            throw BusinessRuntimeException.getInstance("请输入正确的手机号");
+        }
+        if (type == 2 && !Validator.isEmail(login)) {
+            throw BusinessRuntimeException.getInstance("请输入正确的邮箱");
+        }
+        // 所有合法账号在查询前限速,不让账号存在性决定限速响应。
+        // 使用直连地址,不信任客户端可伪造的X-Forwarded-For。
+        String ip = request.getRemoteAddr();
+        String accountHash = cn.hutool.crypto.digest.DigestUtil.sha256Hex(type + ":" + cid + ":" + login);
+        if (!redisService.setNx("yhShop:loginCode:ip:" + ip, "1", 2L)) return;
+        if (!redisService.setNx("yhShop:loginCode:account:" + accountHash, "1", 60L)) return;
+        if (type == 1) {
+            badIntentionOpService.checkHandleBadUserOp(login, verifyCode, ticket, randStr, request);
+        }
+        User user = userMapper.selectOne(Wrappers.lambdaQuery(User.class)
+                .eq(type == 1, User::getLoginPhone, login)
+                .eq(type == 2, User::getEmail, login).last("limit 1"));
+        if (user == null) return;
+        YhShop yhShop = yhShopMapper.selectOne(Wrappers.lambdaQuery(YhShop.class)
+                .eq(YhShop::getVerifyStatus, YhShop.Status.success)
+                .eq(YhShop::getUserId, user.getId()).last("limit 1"));
+        if (yhShop == null) return;
+        String cacheKey = RedisService.key.YH_SHOP_BACK_LOGIN_KEY.getName() + login;
+        String code = StringUtil.getRandomCodeStr(6);
+        try {
+            if (type == 1) {
+                SmsUtil.sendTencent(cid, login, code);
+            } else {
+                if (mailService.sendLoginCodeEmailToPeople(code, login) == null) return;
+            }
+            redisService.set(cacheKey, code, RedisService.key.YH_SHOP_BACK_LOGIN_KEY.getTimeout());
+        } catch (Exception e) {
+            // 发送渠道错误不外返,避免只在真实店主账号出现可区分的响应。
+            log.error("小店登录验证码发送失败", e);
+        }
 	}
 
 	@Override

+ 1 - 2
netflix-web/src/main/java/com/cyksj/web/controller/manage/goods/shop/YhShopLoginController.java

@@ -64,10 +64,9 @@ public class YhShopLoginController {
 	 * 获取登录验证码
 	 */
 	@GetMapping("/get/LoginCode")
-	@NoSubmit
 	public Result getLoginCode(@RequestParam(defaultValue = "1") Integer type, String login, Integer cid, String verifyCode, String ticket, String randStr) {
 		yhShopManageService.getLoginCode(type, login, cid, verifyCode, ticket, randStr);
-		return GatewayResponse.SUCCESS.newBuilder().toResult();
+		return GatewayResponse.SUCCESS.newBuilder().setMsg("如果账号符合登录条件,验证码将发送至对应账号").toResult();
 	}
 
 	/**