Browse Source

手机注册、登录接口

zhaopeiqing 8 months ago
parent
commit
57b6241569
24 changed files with 511 additions and 11 deletions
  1. 41 0
      yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/validation/ValidationUtils.java
  2. 2 0
      yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/enums/ErrorCodeConstants.java
  3. 2 1
      yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/enums/sms/SmsSceneEnum.java
  4. 14 0
      yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/auth/AuthController.java
  5. 3 0
      yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/auth/vo/AuthPermissionInfoRespVO.java
  6. 3 0
      yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/notify/vo/message/NotifyMessagePageReqVO.java
  7. 3 0
      yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/notify/vo/message/NotifyMessageRespVO.java
  8. 8 0
      yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/user/UserProfileController.java
  9. 23 0
      yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/user/vo/profile/UserProfileResetPasswordReqVO.java
  10. 4 0
      yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/notify/NotifyMessageDO.java
  11. 4 0
      yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/user/AdminUserDO.java
  12. 1 0
      yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/notify/NotifyMessageMapper.java
  13. 110 0
      yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/framework/sms/core/client/impl/FeigeSmsClient.java
  14. 1 0
      yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/framework/sms/core/client/impl/SmsClientFactoryImpl.java
  15. 1 0
      yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/framework/sms/core/enums/SmsChannelEnum.java
  16. 16 0
      yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/auth/AdminAuthService.java
  17. 38 2
      yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/auth/AdminAuthServiceImpl.java
  18. 27 0
      yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/register/RegisterService.java
  19. 145 0
      yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/register/RegisterServiceImpl.java
  20. 2 2
      yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/sms/SmsTemplateServiceImpl.java
  21. 18 0
      yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/user/AdminUserService.java
  22. 34 0
      yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/user/AdminUserServiceImpl.java
  23. 1 1
      yudao-server/src/main/resources/application-local.yaml
  24. 10 5
      yudao-server/src/main/resources/application.yaml

+ 41 - 0
yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/validation/ValidationUtils.java

@@ -24,6 +24,9 @@ public class ValidationUtils {
 
     private static final Pattern PATTERN_XML_NCNAME = Pattern.compile("[a-zA-Z_][\\-_.0-9_a-zA-Z$]*");
 
+    // 定义特殊符号集合
+    private static final String SPECIAL_CHARACTERS = "!@#$%^&*()_+{}:\"<>?";
+
     public static boolean isMobile(String mobile) {
         return StringUtils.hasText(mobile)
                 && PATTERN_MOBILE.matcher(mobile).matches();
@@ -52,4 +55,42 @@ public class ValidationUtils {
         }
     }
 
+    /**
+     * 验证密码是否有效
+     * 密码必须包含数字、大写字母、小写字母、特殊符号中的3种,且长度为9-30位
+     * @param password 密码字符串
+     * @return 验证结果
+     */
+    public static boolean isValidPassword(String password) {
+        if (password == null || password.length() < 9 || password.length() > 30) {
+            return false;
+        }
+
+        boolean hasDigit = false;
+        boolean hasUpper = false;
+        boolean hasLower = false;
+        boolean hasSpecial = false;
+
+        for (char ch : password.toCharArray()) {
+            if (Character.isDigit(ch)) {
+                hasDigit = true;
+            } else if (Character.isUpperCase(ch)) {
+                hasUpper = true;
+            } else if (Character.isLowerCase(ch)) {
+                hasLower = true;
+            } else if (SPECIAL_CHARACTERS.indexOf(ch) >= 0) {
+                hasSpecial = true;
+            }
+        }
+
+        // 至少包含3种类型
+        int count = 0;
+        if (hasDigit) count++;
+        if (hasUpper) count++;
+        if (hasLower) count++;
+        if (hasSpecial) count++;
+
+        return count >= 3;
+    }
+
 }

+ 2 - 0
yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/enums/ErrorCodeConstants.java

@@ -42,6 +42,8 @@ public interface ErrorCodeConstants {
     ErrorCode USER_PASSWORD_FAILED = new ErrorCode(1_002_003_005, "用户密码校验失败");
     ErrorCode USER_IS_DISABLE = new ErrorCode(1_002_003_006, "名字为【{}】的用户已被禁用");
     ErrorCode USER_COUNT_MAX = new ErrorCode(1_002_003_008, "创建用户失败,原因:超过租户最大租户配额({})!");
+    ErrorCode USER_PASSWORD_INCONSISTENT_FAILED = new ErrorCode(1_002_003_009, "新密码和确认密码不一致");
+    ErrorCode USER_PASSWORD_SIMPLE_FAILED = new ErrorCode(1_002_003_010, "密码必须包含数字、大写字母、小写字母、特殊符号中的3种,且长度为9-30位");
 
     // ========== 部门模块 1-002-004-000 ==========
     ErrorCode DEPT_NAME_DUPLICATE = new ErrorCode(1_002_004_000, "已经存在该名字的部门");

+ 2 - 1
yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/enums/sms/SmsSceneEnum.java

@@ -16,10 +16,11 @@ import java.util.Arrays;
 @AllArgsConstructor
 public enum SmsSceneEnum implements IntArrayValuable {
 
-    MEMBER_LOGIN(1, "user-sms-login", "会员用户 - 手机号登"),
+    MEMBER_LOGIN(1, "user-sms-login", "会员用户 - 手机号登"),
     MEMBER_UPDATE_MOBILE(2, "user-update-mobile", "会员用户 - 修改手机"),
     MEMBER_UPDATE_PASSWORD(3, "user-update-password", "会员用户 - 修改密码"),
     MEMBER_RESET_PASSWORD(4, "user-reset-password", "会员用户 - 忘记密码"),
+    MEMBER_REGISTER(5, "user-sms-register", "会员用户 - 手机号注册"),
 
     ADMIN_MEMBER_LOGIN(21, "admin-sms-login", "后台用户 - 手机号登录");
 

+ 14 - 0
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/auth/AuthController.java

@@ -132,6 +132,20 @@ public class AuthController {
         return success(true);
     }
 
+    @PostMapping("/sms-register")
+    @PermitAll
+    @Operation(summary = "使用验证码注册并登录")
+    public CommonResult<AuthLoginRespVO> smsRegister(@RequestBody @Valid AuthSmsLoginReqVO reqVO) {
+        return success(authService.smsRegister(reqVO));
+    }
+
+    @PostMapping("/sms-reset-password")
+    @PermitAll
+    @Operation(summary = "使用验证码重置密码")
+    public CommonResult<AuthLoginRespVO> smsResetPassword(@RequestBody @Valid AuthSmsLoginReqVO reqVO) {
+        return success(authService.smsResetPassword(reqVO));
+    }
+
     // ========== 社交登录相关 ==========
 
     @GetMapping("/social-auth-redirect")

+ 3 - 0
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/auth/vo/AuthPermissionInfoRespVO.java

@@ -47,6 +47,9 @@ public class AuthPermissionInfoRespVO {
         @Schema(description = "部门编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "2048")
         private Long deptId;
 
+        @Schema(description = "当前租户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
+        private Long tenantId;
+
     }
 
     @Schema(description = "管理后台 - 登录用户的菜单信息 Response VO")

+ 3 - 0
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/notify/vo/message/NotifyMessagePageReqVO.java

@@ -29,6 +29,9 @@ public class NotifyMessagePageReqVO extends PageParam {
     @Schema(description = "模版类型", example = "2")
     private Integer templateType;
 
+    @Schema(description = "标题", example = "标题")
+    private String title;
+
     @Schema(description = "创建时间")
     @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
     private LocalDateTime[] createTime;

+ 3 - 0
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/notify/vo/message/NotifyMessageRespVO.java

@@ -19,6 +19,9 @@ public class NotifyMessageRespVO {
     @Schema(description = "用户类型,参见 UserTypeEnum 枚举", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
     private Byte userType;
 
+    @Schema(description = "标题", requiredMode = Schema.RequiredMode.REQUIRED, example = "标题")
+    private String title;
+
     @Schema(description = "模版编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "13013")
     private Long templateId;
 

+ 8 - 0
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/user/UserProfileController.java

@@ -4,6 +4,7 @@ import cn.hutool.core.collection.CollUtil;
 import cn.iocoder.yudao.framework.common.enums.UserTypeEnum;
 import cn.iocoder.yudao.framework.common.pojo.CommonResult;
 import cn.iocoder.yudao.framework.datapermission.core.annotation.DataPermission;
+import cn.iocoder.yudao.module.system.controller.admin.user.vo.profile.UserProfileResetPasswordReqVO;
 import cn.iocoder.yudao.module.system.controller.admin.user.vo.profile.UserProfileRespVO;
 import cn.iocoder.yudao.module.system.controller.admin.user.vo.profile.UserProfileUpdatePasswordReqVO;
 import cn.iocoder.yudao.module.system.controller.admin.user.vo.profile.UserProfileUpdateReqVO;
@@ -86,6 +87,13 @@ public class UserProfileController {
         return success(true);
     }
 
+    @PutMapping("/reset-password")
+    @Operation(summary = "重置用户个人密码")
+    public CommonResult<Boolean> resetUserProfilePassword(@Valid @RequestBody UserProfileResetPasswordReqVO reqVO) {
+        userService.resetUserPassword(getLoginUserId(), reqVO);
+        return success(true);
+    }
+
     @RequestMapping(value = "/update-avatar",
             method = {RequestMethod.POST, RequestMethod.PUT}) // 解决 uni-app 不支持 Put 上传文件的问题
     @Operation(summary = "上传用户个人头像")

+ 23 - 0
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/user/vo/profile/UserProfileResetPasswordReqVO.java

@@ -0,0 +1,23 @@
+package cn.iocoder.yudao.module.system.controller.admin.user.vo.profile;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+import org.hibernate.validator.constraints.Length;
+
+import javax.validation.constraints.NotEmpty;
+
+@Schema(description = "管理后台 - 用户个人中心更新密码 Request VO")
+@Data
+public class UserProfileResetPasswordReqVO {
+
+    @Schema(description = "新密码", requiredMode = Schema.RequiredMode.REQUIRED, example = "123456")
+    @NotEmpty(message = "旧密码不能为空")
+    @Length(min = 4, max = 16, message = "密码长度为 4-16 位")
+    private String newPassword;
+    // 密码必须包含数字、大写字母、小写字母、特殊符号中的3种,且长度为9-30位
+    @Schema(description = "确认密码", requiredMode = Schema.RequiredMode.REQUIRED, example = "123456")
+    @NotEmpty(message = "新密码不能为空")
+    @Length(min = 4, max = 16, message = "密码长度为 4-16 位")
+    private String confirmPassword;
+
+}

+ 4 - 0
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/notify/NotifyMessageDO.java

@@ -46,6 +46,10 @@ public class NotifyMessageDO extends BaseDO {
      * 枚举 {@link UserTypeEnum}
      */
     private Integer userType;
+    /**
+     * 站内信标题
+     */
+    private String title;
 
     // ========= 模板相关字段 =========
 

+ 4 - 0
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/user/AdminUserDO.java

@@ -92,5 +92,9 @@ public class AdminUserDO extends TenantBaseDO {
      * 最后登录时间
      */
     private LocalDateTime loginDate;
+    /**
+     * 当前租户编号
+     */
+    private Long tenantId;
 
 }

+ 1 - 0
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/notify/NotifyMessageMapper.java

@@ -20,6 +20,7 @@ public interface NotifyMessageMapper extends BaseMapperX<NotifyMessageDO> {
         return selectPage(reqVO, new LambdaQueryWrapperX<NotifyMessageDO>()
                 .eqIfPresent(NotifyMessageDO::getUserId, reqVO.getUserId())
                 .eqIfPresent(NotifyMessageDO::getUserType, reqVO.getUserType())
+                .eqIfPresent(NotifyMessageDO::getTitle, reqVO.getTitle())
                 .likeIfPresent(NotifyMessageDO::getTemplateCode, reqVO.getTemplateCode())
                 .eqIfPresent(NotifyMessageDO::getTemplateType, reqVO.getTemplateType())
                 .betweenIfPresent(NotifyMessageDO::getCreateTime, reqVO.getCreateTime())

+ 110 - 0
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/framework/sms/core/client/impl/FeigeSmsClient.java

@@ -0,0 +1,110 @@
+package cn.iocoder.yudao.module.system.framework.sms.core.client.impl;
+
+import cn.hutool.core.codec.Base64;
+import cn.hutool.core.lang.Assert;
+import cn.hutool.core.map.MapUtil;
+import cn.hutool.core.util.StrUtil;
+import cn.hutool.crypto.digest.DigestUtil;
+import cn.hutool.crypto.digest.HmacAlgorithm;
+import cn.hutool.http.HttpUtil;
+import cn.iocoder.yudao.framework.common.core.KeyValue;
+import cn.iocoder.yudao.framework.common.util.collection.MapUtils;
+import cn.iocoder.yudao.framework.common.util.json.JsonUtils;
+import cn.iocoder.yudao.module.system.framework.sms.core.client.dto.SmsReceiveRespDTO;
+import cn.iocoder.yudao.module.system.framework.sms.core.client.dto.SmsSendRespDTO;
+import cn.iocoder.yudao.module.system.framework.sms.core.client.dto.SmsTemplateRespDTO;
+import cn.iocoder.yudao.module.system.framework.sms.core.enums.SmsTemplateAuditStatusEnum;
+import cn.iocoder.yudao.module.system.framework.sms.core.property.SmsChannelProperties;
+import com.alibaba.fastjson.JSON;
+import org.apache.http.HttpEntity;
+import org.apache.http.HttpResponse;
+import org.apache.http.client.HttpClient;
+import org.apache.http.client.methods.HttpPost;
+import org.apache.http.entity.StringEntity;
+import org.apache.http.impl.client.HttpClients;
+import org.apache.http.util.EntityUtils;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+
+/**
+ * 飞鸽云短信功能实现
+ *
+ * 参见 <a href="https://cloud.tencent.com/document/product/382/52077">文档</a>
+ *
+ * @author shiwp
+ */
+public class FeigeSmsClient extends AbstractSmsClient {
+
+    public FeigeSmsClient(SmsChannelProperties properties) {
+        super(properties);
+        Assert.notEmpty(properties.getApiKey(), "apiKey 不能为空");
+        Assert.notEmpty(properties.getApiSecret(), "apiSecret 不能为空");
+    }
+
+    @Override
+    protected void doInit() {
+    }
+
+    @Override
+    public SmsSendRespDTO sendSms(Long sendLogId, String mobile,
+                                  String apiTemplateId, List<KeyValue<String, Object>> templateParams) throws Throwable {
+        HttpClient httpClient = HttpClients.createDefault();
+        HttpPost httpPost = new HttpPost("https://api.4321.sh/sms/template");
+        httpPost.addHeader("Content-Type", "application/json");
+        Map<String, Object> map = new HashMap<>();
+        map.put("apikey", properties.getApiKey());// api接口账号
+        map.put("secret", properties.getApiSecret());// api接口秘钥
+        map.put("sign_id", 101760);// 签名id
+        map.put("template_id", apiTemplateId);// 模板id
+        map.put("mobile", mobile);// 手机号
+        String content = MapUtils.convertMap(templateParams).get("code").toString();
+        map.put("content", content);
+        String json = JSON.toJSONString(map);
+        httpPost.setEntity(new StringEntity(json, "UTF-8"));
+        HttpResponse response = httpClient.execute(httpPost);
+        HttpEntity entity = response.getEntity();
+        String res = EntityUtils.toString(entity);
+        // 解析结果
+        Map<?, ?> responseObj = JsonUtils.parseObject(res, Map.class);
+        String code = MapUtil.getStr(responseObj, "code");
+        return new SmsSendRespDTO().setSuccess(Objects.equals(code, "0")).setSerialNo(StrUtil.uuid())
+                .setApiCode(code).setApiMsg(MapUtil.getStr(responseObj, "msg"));
+    }
+
+    /**
+     * 构建请求地址
+     *
+     * 参见 <a href="https://developers.dingtalk.com/document/app/custom-robot-access/title-nfv-794-g71">文档</a>
+     *
+     * @param path 请求路径
+     * @return 请求地址
+     */
+    @SuppressWarnings("SameParameterValue")
+    private String buildUrl(String path) {
+        // 生成 timestamp
+        long timestamp = System.currentTimeMillis();
+        // 生成 sign
+        String secret = properties.getApiSecret();
+        String stringToSign = timestamp + "\n" + secret;
+        byte[] signData = DigestUtil.hmac(HmacAlgorithm.HmacSHA256, StrUtil.bytes(secret)).digest(stringToSign);
+        String sign = Base64.encode(signData);
+        // 构建最终 URL
+        return String.format("https://api.4321.sh/sms/template/%s?access_token=%s&timestamp=%d&sign=%s",
+                path, properties.getApiKey(), timestamp, sign);
+    }
+
+    @Override
+    public List<SmsReceiveRespDTO> parseSmsReceiveStatus(String text) {
+        throw new UnsupportedOperationException("模拟短信客户端,暂时无需解析回调");
+    }
+
+    @Override
+    public SmsTemplateRespDTO getSmsTemplate(String apiTemplateId) {
+        return new SmsTemplateRespDTO().setId(apiTemplateId).setContent("")
+                .setAuditStatus(SmsTemplateAuditStatusEnum.SUCCESS.getStatus()).setAuditReason("");
+    }
+
+}

+ 1 - 0
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/framework/sms/core/client/impl/SmsClientFactoryImpl.java

@@ -78,6 +78,7 @@ public class SmsClientFactoryImpl implements SmsClientFactory {
             case ALIYUN: return new AliyunSmsClient(properties);
             case DEBUG_DING_TALK: return new DebugDingTalkSmsClient(properties);
             case TENCENT: return new TencentSmsClient(properties);
+            case FEIGE: return new FeigeSmsClient(properties);
         }
         // 创建失败,错误日志 + 抛出异常
         log.error("[createSmsClient][配置({}) 找不到合适的客户端实现]", properties);

+ 1 - 0
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/framework/sms/core/enums/SmsChannelEnum.java

@@ -17,6 +17,7 @@ public enum SmsChannelEnum {
     DEBUG_DING_TALK("DEBUG_DING_TALK", "调试(钉钉)"),
     ALIYUN("ALIYUN", "阿里云"),
     TENCENT("TENCENT", "腾讯云"),
+    FEIGE("FEIGE", "飞鸽云"),
 //    HUA_WEI("HUA_WEI", "华为云"),
     ;
 

+ 16 - 0
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/auth/AdminAuthService.java

@@ -46,6 +46,22 @@ public interface AdminAuthService {
      */
     void sendSmsCode(AuthSmsSendReqVO reqVO);
 
+    /**
+     * 使用验证码注册
+     *
+     * @param reqVO 登录信息
+     * @return 登录结果
+     */
+    AuthLoginRespVO smsRegister(AuthSmsLoginReqVO reqVO);
+
+    /**
+     * 使用验证码重置密码
+     *
+     * @param reqVO 登录信息
+     * @return 登录结果
+     */
+    AuthLoginRespVO smsResetPassword(AuthSmsLoginReqVO reqVO);
+
     /**
      * 短信登录
      *

+ 38 - 2
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/auth/AdminAuthServiceImpl.java

@@ -11,6 +11,7 @@ import cn.iocoder.yudao.module.system.api.sms.SmsCodeApi;
 import cn.iocoder.yudao.module.system.api.social.dto.SocialUserBindReqDTO;
 import cn.iocoder.yudao.module.system.api.social.dto.SocialUserRespDTO;
 import cn.iocoder.yudao.module.system.controller.admin.auth.vo.*;
+import cn.iocoder.yudao.module.system.controller.admin.user.vo.user.UserSaveReqVO;
 import cn.iocoder.yudao.module.system.convert.auth.AuthConvert;
 import cn.iocoder.yudao.module.system.dal.dataobject.oauth2.OAuth2AccessTokenDO;
 import cn.iocoder.yudao.module.system.dal.dataobject.user.AdminUserDO;
@@ -112,17 +113,52 @@ public class AdminAuthServiceImpl implements AdminAuthService {
     @Override
     public void sendSmsCode(AuthSmsSendReqVO reqVO) {
         // 登录场景,验证是否存在
-        if (userService.getUserByMobile(reqVO.getMobile()) == null) {
+        if (reqVO.getScene() != 5 && userService.getUserByMobile(reqVO.getMobile()) == null) {
             throw exception(AUTH_MOBILE_NOT_EXISTS);
         }
         // 发送验证码
         smsCodeApi.sendSmsCode(AuthConvert.INSTANCE.convert(reqVO).setCreateIp(getClientIP()));
     }
 
+    @Override
+    public AuthLoginRespVO smsRegister(AuthSmsLoginReqVO reqVO) {
+        // 校验验证码
+        smsCodeApi.useSmsCode(AuthConvert.INSTANCE.convert(reqVO, SmsSceneEnum.MEMBER_REGISTER.getScene(), getClientIP()));
+        // 创建用户信息
+        UserSaveReqVO userSaveReqVO = new UserSaveReqVO();
+        userSaveReqVO.setUsername(reqVO.getMobile());
+        userSaveReqVO.setNickname(reqVO.getMobile());
+        userSaveReqVO.setMobile(reqVO.getMobile());
+        userSaveReqVO.setPassword(reqVO.getMobile());
+        Long id = userService.smsRegister(userSaveReqVO);
+        // 获得用户信息
+        AdminUserDO user = userService.getUserByMobile(reqVO.getMobile());
+        if (user == null) {
+            throw exception(USER_NOT_EXISTS);
+        }
+        // 创建 Token 令牌,记录登录日志
+        return createTokenAfterLoginSuccess(user.getId(), reqVO.getMobile(), LoginLogTypeEnum.LOGIN_MOBILE);
+    }
+
+    @Override
+    public AuthLoginRespVO smsResetPassword(AuthSmsLoginReqVO reqVO) {
+        // 校验验证码
+        smsCodeApi.useSmsCode(AuthConvert.INSTANCE.convert(reqVO, SmsSceneEnum.MEMBER_RESET_PASSWORD.getScene(), getClientIP()));
+
+        // 获得用户信息
+        AdminUserDO user = userService.getUserByMobile(reqVO.getMobile());
+        if (user == null) {
+            throw exception(USER_NOT_EXISTS);
+        }
+
+        // 创建 Token 令牌,记录登录日志
+        return createTokenAfterLoginSuccess(user.getId(), reqVO.getMobile(), LoginLogTypeEnum.LOGIN_MOBILE);
+    }
+
     @Override
     public AuthLoginRespVO smsLogin(AuthSmsLoginReqVO reqVO) {
         // 校验验证码
-        smsCodeApi.useSmsCode(AuthConvert.INSTANCE.convert(reqVO, SmsSceneEnum.ADMIN_MEMBER_LOGIN.getScene(), getClientIP()));
+        smsCodeApi.useSmsCode(AuthConvert.INSTANCE.convert(reqVO, SmsSceneEnum.MEMBER_LOGIN.getScene(), getClientIP()));
 
         // 获得用户信息
         AdminUserDO user = userService.getUserByMobile(reqVO.getMobile());

+ 27 - 0
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/register/RegisterService.java

@@ -0,0 +1,27 @@
+//package cn.iocoder.yudao.module.system.service.register;
+//
+//import cn.iocoder.yudao.module.system.controller.admin.auth.vo.AuthLoginRespVO;
+//import cn.iocoder.yudao.module.system.controller.admin.register.vo.RegisterSendSmsCodeReqVO;
+//import cn.iocoder.yudao.module.system.controller.admin.register.vo.RegisterSmsSendReqVO;
+//
+///**
+// * 管理后台的注册 Service 接口
+// */
+//public interface RegisterService {
+//
+//    /**
+//     * 发送注册验证码
+//     *
+//     * @param reqVO 发送请求
+//     */
+//    void sendSmsCode(RegisterSmsSendReqVO reqVO);
+//
+//    /**
+//     * 使用验证码注册
+//     *
+//     * @param reqVO 登录信息
+//     * @return 登录结果
+//     */
+//    AuthLoginRespVO smsRegister(RegisterSendSmsCodeReqVO reqVO);
+//
+//}

+ 145 - 0
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/register/RegisterServiceImpl.java

@@ -0,0 +1,145 @@
+//package cn.iocoder.yudao.module.system.service.register;
+//
+//import cn.hutool.core.util.ObjectUtil;
+//import cn.iocoder.yudao.framework.common.enums.UserTypeEnum;
+//import cn.iocoder.yudao.framework.common.util.monitor.TracerUtils;
+//import cn.iocoder.yudao.framework.common.util.servlet.ServletUtils;
+//import cn.iocoder.yudao.module.system.api.logger.dto.LoginLogCreateReqDTO;
+//import cn.iocoder.yudao.module.system.api.sms.SmsCodeApi;
+//import cn.iocoder.yudao.module.system.controller.admin.auth.vo.AuthLoginRespVO;
+//import cn.iocoder.yudao.module.system.controller.admin.register.vo.RegisterSendSmsCodeReqVO;
+//import cn.iocoder.yudao.module.system.controller.admin.register.vo.RegisterSmsSendReqVO;
+//import cn.iocoder.yudao.module.system.controller.admin.user.vo.user.UserSaveReqVO;
+//import cn.iocoder.yudao.module.system.convert.auth.AuthConvert;
+//import cn.iocoder.yudao.module.system.convert.register.RegisterConvert;
+//import cn.iocoder.yudao.module.system.dal.dataobject.oauth2.OAuth2AccessTokenDO;
+//import cn.iocoder.yudao.module.system.dal.dataobject.user.AdminUserDO;
+//import cn.iocoder.yudao.module.system.enums.logger.LoginLogTypeEnum;
+//import cn.iocoder.yudao.module.system.enums.logger.LoginResultEnum;
+//import cn.iocoder.yudao.module.system.enums.oauth2.OAuth2ClientConstants;
+//import cn.iocoder.yudao.module.system.enums.sms.SmsSceneEnum;
+//import cn.iocoder.yudao.module.system.service.logger.LoginLogService;
+//import cn.iocoder.yudao.module.system.service.member.MemberService;
+//import cn.iocoder.yudao.module.system.service.oauth2.OAuth2TokenService;
+//import cn.iocoder.yudao.module.system.service.social.SocialUserService;
+//import cn.iocoder.yudao.module.system.service.user.AdminUserService;
+//import com.xingyuv.captcha.service.CaptchaService;
+//import lombok.extern.slf4j.Slf4j;
+//import org.springframework.data.redis.core.RedisTemplate;
+//import org.springframework.stereotype.Service;
+//
+//import javax.annotation.Resource;
+//import javax.validation.Validator;
+//
+//import java.util.Objects;
+//
+//import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
+//import static cn.iocoder.yudao.framework.common.util.servlet.ServletUtils.getClientIP;
+//import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.USER_NOT_EXISTS;
+//
+///**
+// * Register Service 实现类
+// *
+// * @author 芋道源码
+// */
+//@Service
+//@Slf4j
+//public class RegisterServiceImpl implements RegisterService {
+//
+//    @Resource
+//    private AdminUserService userService;
+//    @Resource
+//    private LoginLogService loginLogService;
+//    @Resource
+//    private MemberService memberService;
+//    @Resource
+//    private SmsCodeApi smsCodeApi;
+//    @Resource
+//    private OAuth2TokenService oauth2TokenService;
+//
+//    @Override
+//    public void sendSmsCode(RegisterSmsSendReqVO reqVO) {
+//        // 发送验证码
+//        smsCodeApi.sendSmsCode(RegisterConvert.INSTANCE.convert(reqVO).setCreateIp(getClientIP()));
+//    }
+//
+//    @Override
+//    public AuthLoginRespVO smsRegister(RegisterSendSmsCodeReqVO reqVO) {
+//        // 校验验证码
+//        smsCodeApi.useSmsCode(RegisterConvert.INSTANCE.convert(reqVO, SmsSceneEnum.MEMBER_REGISTER.getScene(), getClientIP()));
+//        // 创建用户信息
+//        UserSaveReqVO userSaveReqVO = new UserSaveReqVO();
+//        userSaveReqVO.setUsername(reqVO.getMobile());
+//        userSaveReqVO.setNickname(reqVO.getMobile());
+//        userSaveReqVO.setMobile(reqVO.getMobile());
+//        userSaveReqVO.setPassword(reqVO.getMobile());
+//        Long id = userService.codeRegister(userSaveReqVO);
+//        // 获得用户信息
+//        AdminUserDO user = userService.getUserByMobile(reqVO.getMobile());
+//        if (user == null) {
+//            throw exception(USER_NOT_EXISTS);
+//        }
+//
+//        // 创建 Token 令牌,记录登录日志
+//        return createTokenAfterLoginSuccess(user.getId(), reqVO.getMobile(), LoginLogTypeEnum.LOGIN_MOBILE);
+//    }
+//
+//    private void createLogoutLog(Long userId, Integer userType, Integer logType) {
+//        LoginLogCreateReqDTO reqDTO = new LoginLogCreateReqDTO();
+//        reqDTO.setLogType(logType);
+//        reqDTO.setTraceId(TracerUtils.getTraceId());
+//        reqDTO.setUserId(userId);
+//        reqDTO.setUserType(userType);
+//        if (ObjectUtil.equal(getUserType().getValue(), userType)) {
+//            reqDTO.setUsername(getUsername(userId));
+//        } else {
+//            reqDTO.setUsername(memberService.getMemberUserMobile(userId));
+//        }
+//        reqDTO.setUserAgent(ServletUtils.getUserAgent());
+//        reqDTO.setUserIp(ServletUtils.getClientIP());
+//        reqDTO.setResult(LoginResultEnum.SUCCESS.getResult());
+//        loginLogService.createLoginLog(reqDTO);
+//    }
+//
+//    private String getUsername(Long userId) {
+//        if (userId == null) {
+//            return null;
+//        }
+//        AdminUserDO user = userService.getUser(userId);
+//        return user != null ? user.getUsername() : null;
+//    }
+//
+//    private UserTypeEnum getUserType() {
+//        return UserTypeEnum.ADMIN;
+//    }
+//
+//    private AuthLoginRespVO createTokenAfterLoginSuccess(Long userId, String username, LoginLogTypeEnum logType) {
+//        // 插入登陆日志
+//        createLoginLog(userId, username, logType, LoginResultEnum.SUCCESS);
+//        // 创建访问令牌
+//        OAuth2AccessTokenDO accessTokenDO = oauth2TokenService.createAccessToken(userId, getUserType().getValue(),
+//                OAuth2ClientConstants.CLIENT_ID_DEFAULT, null);
+//        // 构建返回结果
+//        return AuthConvert.INSTANCE.convert(accessTokenDO);
+//    }
+//
+//    private void createLoginLog(Long userId, String username,
+//                                LoginLogTypeEnum logTypeEnum, LoginResultEnum loginResult) {
+//        // 插入登录日志
+//        LoginLogCreateReqDTO reqDTO = new LoginLogCreateReqDTO();
+//        reqDTO.setLogType(logTypeEnum.getType());
+//        reqDTO.setTraceId(TracerUtils.getTraceId());
+//        reqDTO.setUserId(userId);
+//        reqDTO.setUserType(getUserType().getValue());
+//        reqDTO.setUsername(username);
+//        reqDTO.setUserAgent(ServletUtils.getUserAgent());
+//        reqDTO.setUserIp(ServletUtils.getClientIP());
+//        reqDTO.setResult(loginResult.getResult());
+//        loginLogService.createLoginLog(reqDTO);
+//        // 更新最后登录时间
+//        if (userId != null && Objects.equals(LoginResultEnum.SUCCESS.getResult(), loginResult.getResult())) {
+//            userService.updateUserLogin(userId, ServletUtils.getClientIP());
+//        }
+//    }
+//
+//}

+ 2 - 2
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/sms/SmsTemplateServiceImpl.java

@@ -112,8 +112,8 @@ public class SmsTemplateServiceImpl implements SmsTemplateService {
     }
 
     @Override
-    @Cacheable(cacheNames = RedisKeyConstants.SMS_TEMPLATE, key = "#code",
-            unless = "#result == null")
+//    @Cacheable(cacheNames = RedisKeyConstants.SMS_TEMPLATE, key = "#code",
+//            unless = "#result == null")
     public SmsTemplateDO getSmsTemplateByCodeFromCache(String code) {
         return smsTemplateMapper.selectByCode(code);
     }

+ 18 - 0
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/user/AdminUserService.java

@@ -2,6 +2,7 @@ package cn.iocoder.yudao.module.system.service.user;
 
 import cn.hutool.core.collection.CollUtil;
 import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
+import cn.iocoder.yudao.module.system.controller.admin.user.vo.profile.UserProfileResetPasswordReqVO;
 import cn.iocoder.yudao.module.system.controller.admin.user.vo.profile.UserProfileUpdatePasswordReqVO;
 import cn.iocoder.yudao.module.system.controller.admin.user.vo.profile.UserProfileUpdateReqVO;
 import cn.iocoder.yudao.module.system.controller.admin.user.vo.user.*;
@@ -19,6 +20,15 @@ import java.util.*;
  */
 public interface AdminUserService {
 
+
+    /**
+     * 使用验证码注册
+     *
+     * @param createReqVO 用户信息
+     * @return 用户编号
+     */
+    Long smsRegister(@Valid UserSaveReqVO createReqVO);
+
     /**
      * 创建用户
      *
@@ -58,6 +68,14 @@ public interface AdminUserService {
      */
     void updateUserPassword(Long id, @Valid UserProfileUpdatePasswordReqVO reqVO);
 
+    /**
+     * 修改用户个人密码
+     *
+     * @param id 用户编号
+     * @param reqVO 更新用户个人密码
+     */
+    void resetUserPassword(Long id, @Valid UserProfileResetPasswordReqVO reqVO);
+
     /**
      * 更新用户头像
      *

+ 34 - 0
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/user/AdminUserServiceImpl.java

@@ -9,8 +9,10 @@ import cn.iocoder.yudao.framework.common.exception.ServiceException;
 import cn.iocoder.yudao.framework.common.pojo.PageResult;
 import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
 import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
+import cn.iocoder.yudao.framework.common.util.validation.ValidationUtils;
 import cn.iocoder.yudao.framework.datapermission.core.util.DataPermissionUtils;
 import cn.iocoder.yudao.module.infra.api.file.FileApi;
+import cn.iocoder.yudao.module.system.controller.admin.user.vo.profile.UserProfileResetPasswordReqVO;
 import cn.iocoder.yudao.module.system.controller.admin.user.vo.profile.UserProfileUpdatePasswordReqVO;
 import cn.iocoder.yudao.module.system.controller.admin.user.vo.profile.UserProfileUpdateReqVO;
 import cn.iocoder.yudao.module.system.controller.admin.user.vo.user.UserImportExcelVO;
@@ -22,6 +24,7 @@ import cn.iocoder.yudao.module.system.dal.dataobject.dept.UserPostDO;
 import cn.iocoder.yudao.module.system.dal.dataobject.user.AdminUserDO;
 import cn.iocoder.yudao.module.system.dal.mysql.dept.UserPostMapper;
 import cn.iocoder.yudao.module.system.dal.mysql.user.AdminUserMapper;
+import cn.iocoder.yudao.module.system.enums.logger.LoginResultEnum;
 import cn.iocoder.yudao.module.system.service.dept.DeptService;
 import cn.iocoder.yudao.module.system.service.dept.PostService;
 import cn.iocoder.yudao.module.system.service.permission.PermissionService;
@@ -81,6 +84,20 @@ public class AdminUserServiceImpl implements AdminUserService {
     @Resource
     private FileApi fileApi;
 
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public Long smsRegister(UserSaveReqVO createReqVO) {
+        // 1.2 校验正确性
+        validateUserForCreateOrUpdate(null, createReqVO.getUsername(),
+                createReqVO.getMobile(), createReqVO.getEmail(), createReqVO.getDeptId(), createReqVO.getPostIds());
+        // 2.1 插入用户
+        AdminUserDO user = BeanUtils.toBean(createReqVO, AdminUserDO.class);
+        user.setStatus(CommonStatusEnum.ENABLE.getStatus()); // 默认开启
+        user.setPassword(encodePassword(createReqVO.getPassword())); // 加密密码
+        userMapper.insert(user);
+        return user.getId();
+    }
+
     @Override
     @Transactional(rollbackFor = Exception.class)
     @LogRecord(type = SYSTEM_USER_TYPE, subType = SYSTEM_USER_CREATE_SUB_TYPE, bizNo = "{{#user.id}}",
@@ -169,6 +186,23 @@ public class AdminUserServiceImpl implements AdminUserService {
     public void updateUserPassword(Long id, UserProfileUpdatePasswordReqVO reqVO) {
         // 校验旧密码密码
         validateOldPassword(id, reqVO.getOldPassword());
+        if (!ValidationUtils.isValidPassword(reqVO.getNewPassword())) {// 校验密码
+            throw exception(USER_PASSWORD_SIMPLE_FAILED);
+        }
+        // 执行更新
+        AdminUserDO updateObj = new AdminUserDO().setId(id);
+        updateObj.setPassword(encodePassword(reqVO.getNewPassword())); // 加密密码
+        userMapper.updateById(updateObj);
+    }
+
+    @Override
+    public void resetUserPassword(Long id, UserProfileResetPasswordReqVO reqVO) {
+        if (!reqVO.getNewPassword().equals(reqVO.getConfirmPassword())) {// 校验两次密码是否一致
+            throw exception(USER_PASSWORD_INCONSISTENT_FAILED);
+        }
+        if (!ValidationUtils.isValidPassword(reqVO.getNewPassword())) {// 校验密码
+            throw exception(USER_PASSWORD_SIMPLE_FAILED);
+        }
         // 执行更新
         AdminUserDO updateObj = new AdminUserDO().setId(id);
         updateObj.setPassword(encodePassword(reqVO.getNewPassword())); // 加密密码

+ 1 - 1
yudao-server/src/main/resources/application-local.yaml

@@ -71,7 +71,7 @@ spring:
     host: 127.0.0.1 # 地址
     port: 6379 # 端口
     database: 0 # 数据库索引
-    password: 123456 # 密码,建议生产环境开启
+#    password: 123456 # 密码,建议生产环境开启
 
 --- #################### 定时任务相关配置 ####################
 

+ 10 - 5
yudao-server/src/main/resources/application.yaml

@@ -176,7 +176,7 @@ yudao:
     license: MIT
     license-url: https://gitee.com/zhijiantianya/ruoyi-vue-pro/blob/master/LICENSE
   captcha:
-    enable: true # 验证码的开关,默认为 true
+    enable: false # 验证码的开关,默认为 true
   codegen:
     base-package: ${yudao.info.base-package}
     db-schemas: ${spring.datasource.dynamic.datasource.master.name}
@@ -193,6 +193,11 @@ yudao:
       - /admin-api/pay/notify/** # 支付回调通知,不携带租户编号
       - /jmreport/* # 积木报表,无法携带租户编号
       - /admin-api/mp/open/** # 微信公众号开放平台,微信回调接口,无法携带租户编号
+      - /admin-api/system/auth/send-sms-code # 发送短信验证码,和租户无关
+      - /admin-api/system/auth/sms-login # 使用验证码登录,和租户无关
+      - /admin-api/system/auth/sms-register # 使用验证码注册,和租户无关
+      - /admin-api/system/user/profile/reset-password # 使用验证码重置密码,和租户无关
+      - /admin-api/system/auth/login # 使用账号登录,和租户无关
     ignore-tables:
       - system_tenant
       - system_tenant_package
@@ -236,10 +241,10 @@ yudao:
       - tmp_report_data_1
       - tmp_report_data_income
   sms-code: # 短信验证码相关的配置项
-    expire-times: 10m
-    send-frequency: 1m
-    send-maximum-quantity-per-day: 10
-    begin-code: 9999 # 这里配置 9999 的原因是,测试方便。
+    expire-times: 2m
+    send-frequency: 30s
+    send-maximum-quantity-per-day: 1000
+    begin-code: 0001 # 这里配置 9999 的原因是,测试方便。
     end-code: 9999 # 这里配置 9999 的原因是,测试方便。
   trade:
     order: