瀏覽代碼

feature 增加验证码生成逻辑

xiahan 3 周之前
父節點
當前提交
effa6ae59b

+ 3 - 1
qhse-common/src/main/java/com/rongwei/bscommon/system/service/QHSELoginService.java

@@ -3,6 +3,8 @@ package com.rongwei.bscommon.system.service;
 import com.rongwei.rwadmincommon.system.domain.UserLoginVo;
 import com.rongwei.rwcommon.base.R;
 
+import javax.servlet.http.HttpServletRequest;
+
 /**
  * QHSELoginService class
  *
@@ -10,5 +12,5 @@ import com.rongwei.rwcommon.base.R;
  * @date 2025/08/22
  */
 public interface QHSELoginService {
-    R sendSmsCode(UserLoginVo userLogin);
+    R sendSmsCode(UserLoginVo userLogin, HttpServletRequest request);
 }

+ 3 - 0
qhse-common/src/main/java/com/rongwei/bscommon/system/service/RedisService.java

@@ -19,5 +19,8 @@ public interface RedisService {
 
     boolean hasKey(String key);
 
+    boolean removeKey(String key);
+
+    void  updateValueNoUpdateExpireTime(String key, Object value);
 
 }

+ 54 - 15
qhse-common/src/main/java/com/rongwei/bscommon/system/service/impl/QHSELoginServiceImpl.java

@@ -13,10 +13,10 @@ import com.rongwei.rwcommon.utils.StringUtils;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.beans.factory.annotation.Value;
 import org.springframework.cloud.context.config.annotation.RefreshScope;
 import org.springframework.stereotype.Service;
 
+import javax.servlet.http.HttpServletRequest;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
@@ -42,50 +42,89 @@ public class QHSELoginServiceImpl implements QHSELoginService {
     @Autowired
     private AliyunSmsService aliyunSmsService;
 
+    /**
+     * 双因素认证输入账号,密码,手机验证码:
+     * 1、输入用户名密码+手机号验证码双因素登录系统;
+     * 2、如果用户名密码错误,点击【发送验证码】给提示“密码错误”,倒计时30秒,防止连续点击导致频繁操作,------10分钟内密码错误10次锁定5分钟-----
+     * 3、超时天数14天,登录一次可以14天内再次登录不需要再输入账号密码;
+     * 4、系统设置初始密码:Zpmc@2024
+     *
+     * @param userLogin
+     * @param request
+     * @return
+     */
     @Override
-    public R sendSmsCode(UserLoginVo userLogin) {
+    public R sendSmsCode(UserLoginVo userLogin, HttpServletRequest request) {
+
         String username = userLogin.getUsername();
+        // 错误次数
+        int errorNum = 0;
+        if (redisService.hasKey("smscode-error-" + username)) {
+            errorNum = Integer.parseInt(redisService.getRedisCatchObj("smscode-error-" + username).toString());
+        }
+        if (errorNum > 10) {
+            log.error("用户:{},密码错误次数为:{}", username, errorNum + 1);
+            throw new RuntimeException("密码错误次数已超过限制");
+        }
+        String smsErrorKey = "smscode-error-" + username;
         List<SysUserDo> sysUserDos = qhseUserService.list(new LambdaQueryWrapper<SysUserDo>()
                 .eq(BaseDo::getDeleted, "0").eq(SysUserDo::getAccount, username));
-        if(sysUserDos.isEmpty()){
+        if (sysUserDos.isEmpty()) {
             throw new RuntimeException("该账号不存在请重新输入");
         }
-        if(sysUserDos.size() > 1){
+        if (sysUserDos.size() > 1) {
             throw new RuntimeException("该账号不存在请重新输入");
         }
         SysUserDo sysUserDo = sysUserDos.get(0);
         String mobile = sysUserDo.getMobile();
-        if(StringUtils.isBlank(sysUserDo.getMobile())){
+        if (StringUtils.isBlank(sysUserDo.getMobile())) {
             throw new RuntimeException("手机号码不存在");
         }
+        String smsKey = "smscode-" + mobile;
         //密码校验
         String secPas = SecurityUtil.getSaltMd5AndSha(userLogin.getPassword(), sysUserDo.getId());
         if (!secPas.equals(sysUserDo.getPassword())) {
-            throw new RuntimeException("用户名密码不正确");
+            errorNum = errorNum + 1;
+            if (errorNum == 1) {
+                // 新增错误次数
+                redisService.redisCatchInit(smsErrorKey, errorNum, 600);
+            } else {
+                // 防止过期时间更新 只更新value
+                redisService.updateValueNoUpdateExpireTime(smsErrorKey, errorNum);
+            }
+
+            if (errorNum >= 10) {
+                log.error("用户:{},密码错误次数为:{}", username, errorNum);
+                throw new RuntimeException("密码错误次数已超过限制");
+            }
+            throw new RuntimeException("密码错误");
         }
         // 生成6位数验证码
         String smsCode = generateSms();
         Map<String, Object> map = new HashMap<>();
         map.put("smsCode", smsCode);
-        if(!smsCodeConfig.isSendEnabled()){
-            redisService.redisCatchInit("smscode-" + mobile, smsCode, 60);
+        if (!smsCodeConfig.isSendEnabled()) {
+            redisService.redisCatchInit(smsKey, smsCode, 60);
             return R.ok(map);
         }
         try {
-            aliyunSmsService.sendSms(smsCodeConfig.getTempId(),new HashMap<String,String>(){{
-                put("code",smsCode);
-            }},mobile);
-        }catch (Exception e){
+            aliyunSmsService.sendSms(smsCodeConfig.getTempId(), new HashMap<String, String>() {{
+                put("code", smsCode);
+            }}, mobile);
+        } catch (Exception e) {
             log.error("验证码发送失败原因为");
+            throw new RuntimeException(e.getMessage());
         }
-        redisService.redisCatchInit("smscode-" + mobile, smsCode, 60);
-
+        // 验证码60秒过期
+        redisService.redisCatchInit(smsKey, smsCode, 60);
+        redisService.removeKey(smsErrorKey);
         return R.ok(map);
     }
 
-    public  String generateSms() {
+    public String generateSms() {
         int code = new Random().nextInt(1000000); // 生成0-999999的随机数
         return String.format("%06d", code); // 格式化为6位,不足补零
     }
 
+
 }

+ 13 - 0
qhse-common/src/main/java/com/rongwei/bscommon/system/service/impl/RedisServiceImpl.java

@@ -11,6 +11,7 @@ import com.rongwei.rwadmincommon.system.vo.SysUserVo;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.beans.factory.annotation.Value;
 import org.springframework.data.redis.core.RedisTemplate;
+import org.springframework.data.redis.core.ValueOperations;
 import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
 import org.springframework.data.redis.serializer.RedisSerializer;
 import org.springframework.data.redis.serializer.StringRedisSerializer;
@@ -48,6 +49,18 @@ public class RedisServiceImpl implements RedisService {
     public boolean hasKey(String key) {
         return redisTemplate.hasKey(key);
     }
+
+    @Override
+    public boolean removeKey(String key) {
+        return redisTemplate.delete(key);
+    }
+
+    @Override
+    public void updateValueNoUpdateExpireTime(String key, Object value) {
+
+        redisTemplate.opsForValue().set(key,value,0);
+    }
+
     /**
      * redis配置项初始化
      * @param redisTemplate

+ 22 - 0
qhse-common/src/main/java/com/rongwei/bscommon/system/utils/QHSEUtils.java

@@ -78,4 +78,26 @@ public class QHSEUtils {
 
         redisService = autoRedisService;
     }
+
+    public static String getIp(HttpServletRequest request) {
+        String ipAddress = request.getHeader("X-Forwarded-For");
+
+        if (ipAddress == null || ipAddress.isEmpty() || "unknown".equalsIgnoreCase(ipAddress)) {
+            ipAddress = request.getHeader("Proxy-Client-IP");
+        }
+        if (ipAddress == null || ipAddress.isEmpty() || "unknown".equalsIgnoreCase(ipAddress)) {
+            ipAddress = request.getHeader("WL-Proxy-Client-IP");
+        }
+        if (ipAddress == null || ipAddress.isEmpty() || "unknown".equalsIgnoreCase(ipAddress)) {
+            ipAddress = request.getRemoteAddr();
+        }
+
+        // 处理多级代理的情况(取第一个有效IP)
+        if (ipAddress != null && ipAddress.contains(",")) {
+            ipAddress = ipAddress.split(",")[0].trim();
+        }
+
+        return ipAddress;
+    }
+
 }

+ 8 - 3
qhse-server/src/main/java/com/rongwei/controller/QHSELoginController.java

@@ -7,7 +7,12 @@ import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.cloud.context.config.annotation.RefreshScope;
-import org.springframework.web.bind.annotation.*;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import javax.servlet.http.HttpServletRequest;
 
 /**
  * QHSELoginController class
@@ -31,8 +36,8 @@ public class QHSELoginController {
      * @return 发送结果
      */
     @PostMapping("/sms/code")
-    public R sendSmsCode(@RequestBody UserLoginVo userLogin) {
+    public R sendSmsCode(@RequestBody UserLoginVo userLogin, HttpServletRequest request) {
         log.info("发送验证码,开始发送短信");
-        return qhseLoginService.sendSmsCode(userLogin);
+        return qhseLoginService.sendSmsCode(userLogin, request);
     }
 }