Mure 3 tygodni temu
rodzic
commit
f1cc760db8

+ 1 - 1
db/sys_user.sql

@@ -11,7 +11,7 @@ CREATE TABLE `sys_user` (
     `username` VARCHAR(20) COMMENT '用户名',
     `phone` VARCHAR(20) COMMENT '手机号码',
     `phone_area_code` INT COMMENT '手机区号/国家码',
-    `password` VARCHAR(100) NOT NULL COMMENT '密码',
+    `password` VARCHAR(100) COMMENT '密码',
     UNIQUE KEY (`username`),
     UNIQUE KEY (`phone`),
     INDEX `idx_username` (`username`),

+ 10 - 0
src/main/java/com/backendsys/modules/material/controller/MaterialUserController.java

@@ -1,8 +1,10 @@
 package com.backendsys.modules.material.controller;
 
 import com.backendsys.modules.common.aspect.SysLog;
+import com.backendsys.modules.common.config.security.annotations.Anonymous;
 import com.backendsys.modules.common.utils.Result;
 import com.backendsys.modules.material.entity.MaterialAudit;
+import com.backendsys.modules.material.entity.MaterialUser;
 import com.backendsys.modules.material.service.MaterialUserService;
 import io.swagger.v3.oas.annotations.Operation;
 import io.swagger.v3.oas.annotations.tags.Tag;
@@ -41,5 +43,13 @@ public class MaterialUserController {
         return Result.success().put("data", materialUserService.auditMaterialUser(materialAudit));
     }
 
+    @Anonymous
+    @SysLog("注册成为素材用户 (手机号注册)")
+    @Operation(summary = "注册成为素材用户 (手机号注册)")
+    @PostMapping("/api/material/registerMaterialUser")
+    public Result registerMaterialUser(@Validated(MaterialUser.Register.class) @RequestBody MaterialUser materialUser) {
+        return Result.success().put("data", materialUserService.registerMaterialUser(materialUser));
+    }
+
 
 }

+ 28 - 0
src/main/java/com/backendsys/modules/material/entity/MaterialUser.java

@@ -0,0 +1,28 @@
+package com.backendsys.modules.material.entity;
+
+import com.backendsys.entity.System.SysUserDTO;
+import com.backendsys.entity.validator.Phone;
+import jakarta.validation.constraints.*;
+import lombok.Data;
+
+@Data
+public class MaterialUser {
+
+    public static interface Register{}
+
+    @NotEmpty(message="手机号码不能为空", groups = { Register.class })
+    @Phone(message="手机号码格式不正确", groups = { Register.class })
+    @Size(min = 9, max = 20, message = "手机号码长度在 {min}-{max} 字符", groups = { Register.class })
+    private String phone;
+
+    @NotNull(message="验证码不能为空", groups = { Register.class })
+    @Min(value = 100000, message = "验证码长度是 6 位字符", groups = { Register.class })
+    @Max(value = 999999, message = "验证码长度是 6 位字符", groups = { Register.class })
+    private Integer phone_valid_code;
+
+    @NotNull(message="区号/国家码不能为空", groups = { Register.class })
+    @Max(value = 999999, message = "区号/国家码长度不超过 {value} 字符", groups = { Register.class })
+    private Integer phone_area_code;
+    
+    
+}

+ 4 - 0
src/main/java/com/backendsys/modules/material/service/MaterialUserService.java

@@ -1,6 +1,7 @@
 package com.backendsys.modules.material.service;
 
 import com.backendsys.modules.material.entity.MaterialAudit;
+import com.backendsys.modules.material.entity.MaterialUser;
 import com.backendsys.modules.system.entity.SysUserRole;
 import com.backendsys.utils.response.PageEntity;
 
@@ -18,4 +19,7 @@ public interface MaterialUserService {
     // 审核素材用户
     Map<String, Object> auditMaterialUser(MaterialAudit materialAudit);
 
+    // 注册素材用户 (手机号注册)
+    Map<String, Object> registerMaterialUser(MaterialUser materialUser);
+
 }

+ 114 - 4
src/main/java/com/backendsys/modules/material/service/impl/MaterialUserServiceImpl.java

@@ -1,33 +1,59 @@
 package com.backendsys.modules.material.service.impl;
 
+import cn.hutool.core.convert.Convert;
+import cn.hutool.core.util.RandomUtil;
+import cn.hutool.core.bean.BeanUtil;
 import com.backendsys.exception.CustException;
+import com.backendsys.modules.common.config.redis.utils.RedisUtil;
+import com.backendsys.modules.common.config.security.utils.CaptchaUtil;
+import com.backendsys.modules.common.config.security.utils.LockStatusUtil;
 import com.backendsys.modules.common.config.security.utils.SecurityUtil;
 import com.backendsys.modules.material.entity.MaterialAudit;
+import com.backendsys.modules.material.entity.MaterialUser;
 import com.backendsys.modules.material.service.MaterialUserService;
 import com.backendsys.modules.system.dao.SysUserDao;
 import com.backendsys.modules.system.dao.SysUserInfoDao;
 import com.backendsys.modules.system.dao.SysUserRoleDao;
 import com.backendsys.modules.system.dao.SysUserRoleRelationDao;
-import com.backendsys.modules.system.entity.SysUserDTO;
-import com.backendsys.modules.system.entity.SysUserInfo;
-import com.backendsys.modules.system.entity.SysUserRole;
-import com.backendsys.modules.system.entity.SysUserRoleRelation;
+import com.backendsys.modules.system.entity.*;
+import com.backendsys.modules.system.service.SysAuthService;
+import com.backendsys.modules.system.service.SysCommonService;
+import com.backendsys.modules.system.service.SysUserIntegralService;
 import com.backendsys.modules.system.service.SysUserService;
 import com.backendsys.utils.response.PageEntity;
 import com.backendsys.utils.response.PageInfoResult;
 import com.backendsys.utils.v2.PageUtils;
 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+
 import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.core.env.Environment;
+import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
 import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
 
 import java.util.Arrays;
+import java.util.LinkedHashMap;
 import java.util.List;
 import java.util.Map;
 
 @Service
 public class MaterialUserServiceImpl implements MaterialUserService {
 
+    @Value("${spring.application.name}")
+    private String APPLICATION_NAME;
+    @Value("${tencent.sms.debug}")
+    private String SMS_DEBUG;
+
+    @Autowired
+    private Environment env;
+    @Autowired
+    private LockStatusUtil lockStatusUtil;
+    @Autowired
+    private CaptchaUtil captchaUtil;
+    @Autowired
+    private RedisUtil redisUtil;
+
     @Autowired
     private SysUserDao sysUserDao;
     @Autowired
@@ -37,8 +63,14 @@ public class MaterialUserServiceImpl implements MaterialUserService {
     @Autowired
     private SysUserRoleRelationDao sysUserRoleRelationDao;
 
+    @Autowired
+    private SysAuthService sysAuthService;
     @Autowired
     private SysUserService sysUserService;
+    @Autowired
+    private SysCommonService sysCommonService;
+    @Autowired
+    private SysUserIntegralService sysUserIntegralService;
 
     /**
      * 获取素材用户列表 ({ invite_code = Material })
@@ -110,4 +142,82 @@ public class MaterialUserServiceImpl implements MaterialUserService {
         return Map.of("user_id", materialAudit.getUser_id());
     }
 
+
+    // 注册素材用户 (手机号注册)
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public Map<String, Object> registerMaterialUser(MaterialUser materialUser) {
+
+        // 判断是否允许注册
+        // [系统配置] 是否允许系统用户注册
+        Boolean SYSTEM_USER_ALLOW_REGISTER = Convert.toBool(sysCommonService.getCommonByTag("SYSTEM_USER_ALLOW_REGISTER"));
+        if (!SYSTEM_USER_ALLOW_REGISTER) throw new CustException("系统已禁止注册");
+
+        String phone = materialUser.getPhone();
+        Integer phoneAreaCode = materialUser.getPhone_area_code();
+        Integer phoneValidCode = materialUser.getPhone_valid_code();
+
+        String activeProfile = env.getActiveProfiles()[0];
+
+        //if (!"local".equals(activeProfile)) {
+        //    // 判断是否处于登录错误的冻结状态 (2分钟内错误5次,则出现冻结提示)
+        //    lockStatusUtil.checkLockStatus(APPLICATION_NAME + "-register-error", phone);
+        //    // 判断图形验证码是否正确
+        //    if (!captchaUtil.isCaptchaValid(captcha, httpRequestUtil.getKaptchaKey())) {
+        //        loginFail("验证码错误", username, false);
+        //        return null;
+        //    }
+        //}
+
+
+        // 判断短信验证码是否正确
+        if (!"local".equals(activeProfile)) {
+            String redisKey = APPLICATION_NAME + "-sms-register" + "-" + phone;
+            Integer smsCode = redisUtil.getCacheObject(redisKey);
+            // 判断是否发送验证码
+            if ("false".equals(SMS_DEBUG) && smsCode == null) throw new CustException("请先发送短信验证码");
+            // 判断短信验证码是否错误
+            if ("false".equals(SMS_DEBUG) && !smsCode.equals(phoneValidCode)) sysAuthService.loginFail("短信验证码错误", phone, true);
+        }
+
+
+        // [查询] 判断手机号是否存在 (如果存在就直接登录,返回Token)
+        LambdaQueryWrapper<SysUser> queryWrapper = new LambdaQueryWrapper<>();
+        queryWrapper.eq(SysUser::getPhone, phone).eq(SysUser::getPhone_area_code, phoneAreaCode);
+        SysUser sysUserDetail = sysUserDao.selectOne(queryWrapper);
+        if (sysUserDetail != null) {
+            // [已注册] 返回登录信息 (并且7天免登录)
+            SysUserInfo sysUserInfo = sysAuthService.loginSuccess(sysUserDetail.getId(), 1);
+            return BeanUtil.beanToMap(sysUserInfo);
+        } else {
+            // [未注册] 通过校验,并注册
+
+            // 注册
+            SysUserDTO registerEntity = new SysUserDTO();
+            registerEntity.setUsername(phone);
+            registerEntity.setPhone(phone);
+            registerEntity.setPhone_area_code(phoneAreaCode);
+            registerEntity.setInvite_code("Material");
+
+            // 注册时,使用 [素材游客] 权限 (MATERIAL_GUEST)
+            String role_sign = "MATERIAL_GUEST";
+            LambdaQueryWrapper<SysUserRole> wrapperRole = new LambdaQueryWrapper<>();
+            wrapperRole.eq(SysUserRole::getRole_sign, role_sign);
+            SysUserRole roleDetail = sysUserRoleDao.selectOne(wrapperRole);
+            registerEntity.setRole_id(Arrays.asList(roleDetail.getRole_id()));
+
+            // 注册时,审核状态为 待审核 (-1拒绝, 1待审核, 2审核通过)
+            registerEntity.setAudit_status(2);
+            // 随机昵称 (6位)
+            registerEntity.setNickname("用户" + RandomUtil.randomStringUpper(6));
+
+            // 创建用户
+            sysUserDao.insertUser(registerEntity);
+
+            // 初始化用户积分
+            sysUserIntegralService.init(registerEntity.getId());
+
+            return Map.of("user_id", registerEntity.getId());
+        }
+    }
 }

+ 6 - 0
src/main/java/com/backendsys/modules/system/service/SysAuthService.java

@@ -19,4 +19,10 @@ public interface SysAuthService {
     Map<String, Object> register(SysUserDTO sysUserDTO);
     Map<String, Object> forgotPassword(SysUserDTO sysUserDTO);
     Map<String, Object> logout();
+
+    // [方法] 登录失败 (通用) (errMsg: 错误提示文本, username: 用户名, intercept: 是否拦截)
+    void loginFail(String errMsg, String username, Boolean isIntercept);
+    void cleanLoginRequired(String key);
+    // [方法] 登录成功
+    SysUserInfo loginSuccess(Long user_id, Integer is_remember);
 }

+ 3 - 3
src/main/java/com/backendsys/modules/system/service/impl/SysAuthServiceImpl.java

@@ -125,7 +125,7 @@ public class SysAuthServiceImpl implements SysAuthService {
     }
 
     // [方法] 登录失败 (通用) (errMsg: 错误提示文本, username: 用户名, intercept: 是否拦截)
-    private void loginFail(String errMsg, String username, Boolean isIntercept) {
+    public void loginFail(String errMsg, String username, Boolean isIntercept) {
 
         // 验证码是否必填
         Boolean currentCaptchaRequired = captchaUtil.isCaptchaRequired(APPLICATION_NAME + "-login-required-captcha-" + username, 3);
@@ -145,7 +145,7 @@ public class SysAuthServiceImpl implements SysAuthService {
     }
 
     // [方法] 登录成功
-    private SysUserInfo loginSuccess(Long user_id, Integer is_remember) {
+    public SysUserInfo loginSuccess(Long user_id, Integer is_remember) {
 
         // [查询] 登录的用户信息
         SysUserInfo sysUserInfo = sysUserService.selectUserInfo(user_id);
@@ -211,7 +211,7 @@ public class SysAuthServiceImpl implements SysAuthService {
         redisUtil.setCacheObject(APPLICATION_NAME + "-login-required-captcha-" + key, currentErrCount, 1, TimeUnit.MINUTES);
         System.out.println("currentErrCount: " + currentErrCount);
     }
-    private void cleanLoginRequired(String key) {
+    public void cleanLoginRequired(String key) {
         redisUtil.delete(APPLICATION_NAME + "-login-required-captcha-" + key);
     }
 

+ 2 - 0
src/main/resources/mapper/system/SysUserDao.xml

@@ -244,6 +244,7 @@
             <if test="gender != null and gender != ''">, gender</if>
             <if test="avatar != null and avatar != ''">, avatar</if>
             <if test="status != null and status != ''">, status</if>
+            <if test="audit_status != null and audit_status != ''">, audit_status</if>
             <if test="invite_code != null and invite_code != ''">, invite_code</if>
         ) VALUES (@last_user_id
             <if test="nickname != null and nickname != ''">, #{nickname}</if>
@@ -251,6 +252,7 @@
             <if test="gender != null and gender != ''">, #{gender}</if>
             <if test="avatar != null and avatar != ''">, #{avatar}</if>
             <if test="status != null and status != ''">, #{status}</if>
+            <if test="audit_status != null and audit_status != ''">, #{audit_status}</if>
             <if test="invite_code != null and invite_code != ''">, #{invite_code}</if>
         );