30262728@qq.com 2 тижнів тому
батько
коміт
bb43c86c4d

+ 4 - 3
qnfhq-api/src/main/java/com/qnfhq/modules/user/dto/AppLoginDTO.java

@@ -31,6 +31,9 @@ public class AppLoginDTO {
     @NotBlank(message="{NotBlank.loginName}")//账号不能为空
     private String loginName;
 
+    @Schema(title = "区号")
+    private String zone;
+
     @Schema(title = "验证码")
     @NotBlank(message="{NotBlank.code}")//验证码不能为空
     private String code;
@@ -43,9 +46,7 @@ public class AppLoginDTO {
 //    @NotNull(message="登录类型不能为空")
 //    private int signType;
 //
-//    @Schema(title = "区号")
-//    @NotBlank(message="区号不能为空")
-//    private String zone;
+
 
 
 }

+ 5 - 0
qnfhq-api/src/main/java/com/qnfhq/modules/user/dto/AppRegisterDTO.java

@@ -24,6 +24,11 @@ import lombok.Data;
 @Schema(title = "注册表单")
 public class AppRegisterDTO {
 
+
+    @Schema(title = "国家")
+    @NotBlank(message="{NotBlank.country}")//国家不能为空
+    private String country;
+
     @Schema(title = "密码")
     @NotBlank(message="{NotBlank.password}")//密码不能为空
     private String loginPassword;

+ 1 - 0
qnfhq-api/src/main/java/com/qnfhq/modules/user/entity/AppUserEntity.java

@@ -25,6 +25,7 @@ public class AppUserEntity implements Serializable {
 	private Long id;
 
     private String uid;
+    private String country;
     /**
      * 登陆账号
      */

+ 31 - 0
qnfhq-api/src/main/java/com/qnfhq/modules/user/enums/UserStatus.java

@@ -0,0 +1,31 @@
+package com.qnfhq.modules.user.enums;
+
+/**
+ * 用户状态
+ *
+ */
+public enum UserStatus
+{
+    OK(0, "正常"),
+    DISABLE(1, "停用"),
+    DELETED(2, "注销");
+
+    private final Integer code;
+    private final String info;
+
+    UserStatus(Integer code, String info)
+    {
+        this.code = code;
+        this.info = info;
+    }
+
+    public Integer getCode()
+    {
+        return code;
+    }
+
+    public String getInfo()
+    {
+        return info;
+    }
+}

+ 1 - 1
qnfhq-api/src/main/java/com/qnfhq/modules/user/service/AppUserService.java

@@ -17,7 +17,7 @@ public interface AppUserService extends BaseService<AppUserEntity> {
 
     AppUserEntity getUserByEmail(String email);
 
-    AppUserEntity getUserByMobile(String mobile);
+    AppUserEntity getUserByMobile(String mobile,String zone);
 
     AppUserEntity getUserByUserId(Long userId);
 

+ 32 - 15
qnfhq-api/src/main/java/com/qnfhq/modules/user/service/impl/AppUserServiceImpl.java

@@ -1,6 +1,7 @@
 package com.qnfhq.modules.user.service.impl;
 
 import cn.dev33.satoken.stp.StpUtil;
+import cn.hutool.core.lang.Validator;
 import cn.hutool.core.map.MapUtil;
 import cn.hutool.json.JSONObject;
 import cn.hutool.json.JSONUtil;
@@ -12,6 +13,7 @@ import com.qnfhq.common.utils.DateUtils;
 import com.qnfhq.common.utils.IpUtils;
 import com.qnfhq.common.utils.MessageUtils;
 import com.qnfhq.common.utils.Result;
+import com.qnfhq.common.validator.ValidatorUtils;
 import com.qnfhq.constant.ApiConstant;
 import com.qnfhq.modules.user.dao.AppUserDao;
 import com.qnfhq.modules.user.dto.*;
@@ -25,6 +27,7 @@ import com.qnfhq.modules.user.service.*;
 import com.qnfhq.utils.EmailUtils;
 import com.qnfhq.utils.EmailValidUtils;
 import com.qnfhq.utils.OrderUtils;
+import com.qnfhq.utils.password.PasswordStrengthValidator;
 import com.qnfhq.utils.password.PasswordUtils;
 import com.qnfhq.utils.sms.SmsSenderUtil;
 import jakarta.annotation.Resource;
@@ -75,14 +78,17 @@ public class AppUserServiceImpl extends BaseServiceImpl<AppUserDao, AppUserEntit
     public AppUserEntity getUserByEmail(String email) {
         return baseDao.selectOne(new LambdaQueryWrapper<AppUserEntity>()
                 .eq(AppUserEntity::getEmail, email)
+                .eq(AppUserEntity::getStatus, UserStatus.OK.getCode())
                 .last(" limit 1")
         );
     }
 
     @Override
-    public AppUserEntity getUserByMobile(String mobile) {
+    public AppUserEntity getUserByMobile(String mobile,String zone) {
         return baseDao.selectOne(new LambdaQueryWrapper<AppUserEntity>()
                 .eq(AppUserEntity::getPhone, mobile)
+                .eq(AppUserEntity::getZone, zone)
+                .eq(AppUserEntity::getStatus, UserStatus.OK.getCode())
                 .last(" limit 1")
         );
     }
@@ -91,6 +97,7 @@ public class AppUserServiceImpl extends BaseServiceImpl<AppUserDao, AppUserEntit
     public AppUserEntity getUserByUserId(Long userId) {
         return baseDao.selectOne(new LambdaQueryWrapper<AppUserEntity>()
                 .eq(AppUserEntity::getId, userId)
+                .eq(AppUserEntity::getStatus, UserStatus.OK.getCode())
                 .last(" limit 1")
         );
     }
@@ -99,15 +106,17 @@ public class AppUserServiceImpl extends BaseServiceImpl<AppUserDao, AppUserEntit
     public AppUserEntity getUserByActiveCode(String activeCode) {
         return baseDao.selectOne(new LambdaQueryWrapper<AppUserEntity>()
                 .eq(AppUserEntity::getActiveCode, activeCode)
+                .eq(AppUserEntity::getStatus, UserStatus.OK.getCode())
                 .last(" limit 1")
         );
     }
 
-    public AppUserEntity getUserByLoginName(String loginName) {
-        return baseDao.selectOne(new LambdaQueryWrapper<AppUserEntity>()
-                .eq(AppUserEntity::getLoginName, loginName)
-                .last(" limit 1")
-        );
+    public AppUserEntity getUserByLoginName(String loginName,String zone) {
+        if(Validator.isEmail(loginName)) {
+            return getUserByEmail(loginName);
+        } else {
+            return getUserByMobile(loginName,zone);
+        }
     }
 
     /**
@@ -129,6 +138,9 @@ public class AppUserServiceImpl extends BaseServiceImpl<AppUserDao, AppUserEntit
         AppUserEntity appUserEntity = new AppUserEntity();
         //临时邮箱检测
         EmailValidUtils.validateEmail(registerDto.getEmail());
+        //密码强度检测
+        PasswordStrengthValidator.validatePasswordStrength(registerDto.getLoginPassword());
+        log.info("password valid end");
 
         //验证码校验
         String codeType = registerDto.getCodeType();
@@ -141,11 +153,13 @@ public class AppUserServiceImpl extends BaseServiceImpl<AppUserDao, AppUserEntit
         if(Objects.nonNull(appUser)){
             throw new RenException(MessageUtils.message("user.register.email.exisit"));//邮箱已存在
         }
-        appUser = getUserByMobile(registerDto.getPhone());
+        appUser = getUserByMobile(registerDto.getPhone(),registerDto.getZone());
         if(Objects.nonNull(appUser)){
             throw new RenException(MessageUtils.message("user.register.phone.exisit"));//手机号已存在
         }
 
+
+        appUserEntity.setCountry(registerDto.getCountry());
         appUserEntity.setLoginName(registerDto.getEmail().toLowerCase().trim());
         String host = request.getServerName();
         appUserEntity.setHost(host);
@@ -153,7 +167,7 @@ public class AppUserServiceImpl extends BaseServiceImpl<AppUserDao, AppUserEntit
         appUserEntity.setEmail(registerDto.getEmail().toLowerCase().trim());
         appUserEntity.setZone(registerDto.getZone());
         appUserEntity.setPhone(registerDto.getPhone());
-        appUserEntity.setStatus(0);
+        appUserEntity.setStatus(UserStatus.OK.getCode());
         appUserEntity.setIsTest(0);
         appUserEntity.setIsBlack(UserBlackEnum.NORMAL.getCode());
         appUserEntity.setLoginPassword(PasswordUtils.encode(registerDto.getLoginPassword().trim()));
@@ -220,6 +234,7 @@ public class AppUserServiceImpl extends BaseServiceImpl<AppUserDao, AppUserEntit
     @Override
     public Result login(AppLoginDTO dto, HttpServletRequest request)
     {
+        //图形验证码
         if(!captchaService.validate(dto.getUuid(), dto.getCode())) {
             throw new RenException(MessageUtils.message("appUser.login.code.err"));//验证码错误
         }
@@ -227,10 +242,7 @@ public class AppUserServiceImpl extends BaseServiceImpl<AppUserDao, AppUserEntit
         //账号密码失败重试次数
         checkPwdErrTryTimes(dto.getLoginName());
 
-
-//        passwordTryTimes(pwdFailHourKey);
-
-        AppUserEntity appUser = getUserByLoginName(dto.getLoginName());
+        AppUserEntity appUser = getUserByLoginName(dto.getLoginName(),dto.getZone());
         if(appUser==null) {
             throw new RenException(MessageUtils.message("appUser.loginName.or.password.err"));//账号或密码错误
         }
@@ -239,6 +251,11 @@ public class AppUserServiceImpl extends BaseServiceImpl<AppUserDao, AppUserEntit
             checkPwdErrTryTimes(dto.getLoginName());
             throw new RenException(MessageUtils.message("appUser.loginName.or.password.err.limit.chance",ApiConstant.PASSWORD_FAIL_HOUR_TIMES-pwdFailTimes));//账号或密码错误,您还有4次机会
         }
+        //手机验证校验
+        String codeType = UserCodeTypeEnum.LOGIN.name();
+        final String phoneCodeResultKey = String.format("%s%s%s%s%s",CachePrefix.SMS_CODE.getPrefix(),UserCodeTypeEnum.valueOf(codeType).name(),appUser.getZone(),appUser.getPhone(),":result");
+        verifyResult(phoneCodeResultKey);
+
         //是否黑名单
         if(Objects.nonNull(appUser.getIsBlack()) && appUser.getIsBlack() == UserBlackEnum.BLOCK.getCode()){
             throw new RenException(MessageUtils.message("user_is_black"));//您的账号已被列入黑名单,无法登录。
@@ -365,7 +382,7 @@ public class AppUserServiceImpl extends BaseServiceImpl<AppUserDao, AppUserEntit
         }
 
         if(codeType.toLowerCase().equals("register")) {
-            AppUserEntity appUser = getUserByMobile(phone);
+            AppUserEntity appUser = getUserByMobile(phone,zone);
             if(Objects.nonNull(appUser)){
                 throw new RenException(MessageUtils.message("user.register.phone.exist"));//手机号已经存在
             }
@@ -462,7 +479,7 @@ public class AppUserServiceImpl extends BaseServiceImpl<AppUserDao, AppUserEntit
 
 
         //更新密码
-        AppUserEntity appUser = getUserByMobile(phone);
+        AppUserEntity appUser = getUserByMobile(phone,zone);
         if(Objects.isNull(appUser)){
             throw new RenException(MessageUtils.message("user.not.exist"));//用户不存在
         }
@@ -498,7 +515,7 @@ public class AppUserServiceImpl extends BaseServiceImpl<AppUserDao, AppUserEntit
         checkPhoneCode("FIND_PASSWORD",codeDTO.getZone(),codeDTO.getPhone(),codeDTO.getCode());
 
         //更新密码
-        AppUserEntity appUser = getUserByMobile(codeDTO.getPhone());
+        AppUserEntity appUser = getUserByMobile(codeDTO.getPhone(),codeDTO.getZone());
         if(Objects.isNull(appUser)){
             throw new RenException(MessageUtils.message("user.not.exist"));//用户不存在
         }

+ 61 - 0
qnfhq-api/src/main/java/com/qnfhq/utils/password/PasswordStrengthValidator.java

@@ -0,0 +1,61 @@
+package com.qnfhq.utils.password;
+
+import com.qnfhq.common.exception.RenException;
+import com.qnfhq.common.utils.MessageUtils;
+
+/**
+ * 密码强度验证工具类
+ *
+ * @Author: Yelz 30262728@qq.com
+ * @Date: 2025/11/20 13:49
+ * @Description:
+ */
+public class PasswordStrengthValidator {
+
+    /**
+     * 验证密码强度
+     * 8-32个字符
+     * 1个小写
+     * 1个大写
+     * 1个数字
+     * 1个特殊符号 % # $ @ !
+     * @param password 密码
+     */
+    public static void validatePasswordStrength(String password) {
+        if (password == null || password.length() < 8) {
+            throw new RenException(MessageUtils.message("password.length.lt8"));//密码长度不能少于8位
+        }
+
+        if (password.length() > 32) {
+            throw new RenException(MessageUtils.message("password.length.gt32"));//密码长度不能超过32位
+        }
+
+        int strength = 0;
+
+        // 包含数字
+        if (password.matches(".*\\d.*")) {
+            strength++;
+        }
+
+        // 包含小写字母
+        if (password.matches(".*[a-z].*")) {
+            strength++;
+        }
+
+        // 包含大写字母
+        if (password.matches(".*[A-Z].*")) {
+            strength++;
+        }
+
+        // 包含特殊字符
+        if (password.matches(".*[!@#$%^&*()_+\\-=\\[\\]{};':\"\\\\|,.<>\\/?].*")) {
+            strength++;
+        }
+
+        if (strength < 4) {
+            throw new RenException(MessageUtils.message("password.must.include.digit.alpha.sc"));//密码必须包含数字、大小写字母、特殊字符
+        }
+
+    }
+}
+

+ 4 - 0
qnfhq-api/src/main/resources/i18n/messages_zh.properties

@@ -126,3 +126,7 @@ c2c.order.complain.voucher.is.end=\u7533\u8bc9\u5df2\u7ed3\u675f
 c2c.order.complain.voucher.save.fail=\u4fdd\u5b58\u7533\u8bc9\u51ed\u8bc1\u5931\u8d25
 c2c.order.complain.voucher.update.fail=\u4fee\u6539\u7533\u8bc9\u51ed\u8bc1\u5931\u8d25
 c2c.order.complainId.orderId.invalid=\u7533\u8bc9\u7f16\u53f7\u6216\u8ba2\u5355\u7f16\u53f7\u65e0\u6548
+password.length.lt8=\u5bc6\u7801\u957f\u5ea6\u4e0d\u80fd\u5c11\u4e8e8\u4f4d
+password.length.gt32=\u5bc6\u7801\u957f\u5ea6\u4e0d\u80fd\u8d85\u8fc732\u4f4d
+password.must.include.digit.alpha.sc=\u5bc6\u7801\u5fc5\u987b\u5305\u542b\u6570\u5b57\u3001\u5927\u5c0f\u5199\u5b57\u6bcd\u3001\u7279\u6b8a\u5b57\u7b26
+

+ 2 - 1
qnfhq-api/src/main/resources/i18n/validation_zh.properties

@@ -37,4 +37,5 @@ NotNull.orderId=\u8ba2\u5355\u7f16\u53f7\u4e0d\u80fd\u4e3a\u7a7a
 NotBlank.reason=\u7533\u8bc9\u539f\u56e0\u4e0d\u80fd\u4e3a\u7a7a
 NotBlank.remark=\u51ed\u8bc1\u63cf\u8ff0\u4e0d\u80fd\u4e3a\u7a7a
 NotBlank.img1=\u51ed\u8bc1\u622a\u56fe1\u4e0d\u80fd\u4e3a\u7a7a
-NotNull.complainId=\u7533\u8bc9\u7f16\u53f7\u4e0d\u80fd\u4e3a\u7a7a
+NotNull.complainId=\u7533\u8bc9\u7f16\u53f7\u4e0d\u80fd\u4e3a\u7a7a
+NotBlank.country=\u56fd\u5bb6\u4e0d\u80fd\u4e3a\u7a7a

+ 1 - 0
qnfhq-api/src/main/resources/mapper/user/AppUserDao.xml

@@ -5,6 +5,7 @@
 
     <resultMap type="com.qnfhq.modules.user.entity.AppUserEntity" id="appUserMap">
         <result property="id" column="id"/>
+        <result property="country" column="country"/>
         <result property="loginName" column="login_name"/>
         <result property="loginPassword" column="login_password"/>
         <result property="phone" column="phone"/>