diff --git a/yudao-module-member/yudao-module-member-api/src/main/java/cn/iocoder/yudao/module/member/enums/ErrorCodeConstants.java b/yudao-module-member/yudao-module-member-api/src/main/java/cn/iocoder/yudao/module/member/enums/ErrorCodeConstants.java index 25fcdc874..c72e5a2da 100644 --- a/yudao-module-member/yudao-module-member-api/src/main/java/cn/iocoder/yudao/module/member/enums/ErrorCodeConstants.java +++ b/yudao-module-member/yudao-module-member-api/src/main/java/cn/iocoder/yudao/module/member/enums/ErrorCodeConstants.java @@ -12,6 +12,7 @@ public interface ErrorCodeConstants { // ========== 用户相关 1004001000============ ErrorCode USER_NOT_EXISTS = new ErrorCode(1004001000, "用户不存在"); ErrorCode USER_PASSWORD_FAILED = new ErrorCode(1004001001, "密码校验失败"); + ErrorCode USER_MOBILE_USED = new ErrorCode(1004001002, "修改手机失败,该手机号({})已经被使用"); // ========== AUTH 模块 1004003000 ========== ErrorCode AUTH_LOGIN_BAD_CREDENTIALS = new ErrorCode(1004003000, "登录失败,账号密码不正确"); @@ -19,6 +20,7 @@ public interface ErrorCodeConstants { ErrorCode AUTH_TOKEN_EXPIRED = new ErrorCode(1004003004, "Token 已经过期"); ErrorCode AUTH_THIRD_LOGIN_NOT_BIND = new ErrorCode(1004003005, "未绑定账号,需要进行绑定"); ErrorCode AUTH_WEIXIN_MINI_APP_PHONE_CODE_ERROR = new ErrorCode(1004003006, "获得手机号失败"); + ErrorCode AUTH_MOBILE_USED = new ErrorCode(1004003007, "手机号已经被使用"); // ========== 用户收件地址 1004004000 ========== ErrorCode ADDRESS_NOT_EXISTS = new ErrorCode(1004004000, "用户收件地址不存在"); diff --git a/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/app/auth/AppAuthController.java b/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/app/auth/AppAuthController.java index 8a0c48447..34dc0ea14 100644 --- a/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/app/auth/AppAuthController.java +++ b/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/app/auth/AppAuthController.java @@ -77,6 +77,13 @@ public class AppAuthController { return success(true); } + @PostMapping("/validate-sms-code") + @Operation(summary = "校验手机验证码") + public CommonResult validateSmsCode(@RequestBody @Valid AppAuthSmsValidateReqVO reqVO) { + authService.validateSmsCode(getLoginUserId(), reqVO); + return success(true); + } + @PostMapping("/reset-password") @Operation(summary = "重置密码", description = "用户忘记密码时使用") @PreAuthenticated diff --git a/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/app/auth/vo/AppAuthSmsValidateReqVO.java b/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/app/auth/vo/AppAuthSmsValidateReqVO.java new file mode 100644 index 000000000..1a57be74b --- /dev/null +++ b/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/app/auth/vo/AppAuthSmsValidateReqVO.java @@ -0,0 +1,35 @@ +package cn.iocoder.yudao.module.member.controller.app.auth.vo; + +import cn.iocoder.yudao.framework.common.validation.InEnum; +import cn.iocoder.yudao.framework.common.validation.Mobile; +import cn.iocoder.yudao.module.system.enums.sms.SmsSceneEnum; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.experimental.Accessors; +import org.hibernate.validator.constraints.Length; + +import javax.validation.constraints.NotEmpty; +import javax.validation.constraints.NotNull; +import javax.validation.constraints.Pattern; + +@Schema(description = "用户 APP - 校验手机验证码 Request VO") +@Data +@Accessors(chain = true) +public class AppAuthSmsValidateReqVO { + + @Schema(description = "手机号", example = "15601691234") + @Mobile + private String mobile; + + @Schema(description = "发送场景,对应 SmsSceneEnum 枚举", example = "1") + @NotNull(message = "发送场景不能为空") + @InEnum(SmsSceneEnum.class) + private Integer scene; + + @Schema(description = "手机验证码", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + @NotEmpty(message = "手机验证码不能为空") + @Length(min = 4, max = 6, message = "手机验证码长度为 4-6 位") + @Pattern(regexp = "^[0-9]+$", message = "手机验证码必须都是数字") + private String code; + +} diff --git a/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/app/user/AppMemberUserController.java b/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/app/user/AppMemberUserController.java index 6455b25d5..8dd216034 100644 --- a/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/app/user/AppMemberUserController.java +++ b/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/app/user/AppMemberUserController.java @@ -30,14 +30,6 @@ public class AppMemberUserController { @Resource private MemberUserService userService; - @PutMapping("/update") - @Operation(summary = "修改基本信息") - @PreAuthenticated - public CommonResult updateUser(@RequestBody @Valid AppMemberUserUpdateReqVO reqVO) { - userService.updateUser(getLoginUserId(), reqVO); - return success(true); - } - @GetMapping("/get") @Operation(summary = "获得基本信息") @PreAuthenticated @@ -46,10 +38,18 @@ public class AppMemberUserController { return success(MemberUserConvert.INSTANCE.convert(user)); } - @PostMapping("/update-mobile") + @PutMapping("/update") + @Operation(summary = "修改基本信息") + @PreAuthenticated + public CommonResult updateUser(@RequestBody @Valid AppMemberUserUpdateReqVO reqVO) { + userService.updateUser(getLoginUserId(), reqVO); + return success(true); + } + + @PutMapping("/update-mobile") @Operation(summary = "修改用户手机") @PreAuthenticated - public CommonResult updateMobile(@RequestBody @Valid AppUserUpdateMobileReqVO reqVO) { + public CommonResult updateUserMobile(@RequestBody @Valid AppUserUpdateMobileReqVO reqVO) { userService.updateUserMobile(getLoginUserId(), reqVO); return success(true); } diff --git a/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/app/user/vo/AppUserUpdateMobileReqVO.java b/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/app/user/vo/AppUserUpdateMobileReqVO.java index c6ec7a90c..ade0afab4 100644 --- a/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/app/user/vo/AppUserUpdateMobileReqVO.java +++ b/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/app/user/vo/AppUserUpdateMobileReqVO.java @@ -37,12 +37,4 @@ public class AppUserUpdateMobileReqVO { @Pattern(regexp = "^[0-9]+$", message = "手机验证码必须都是数字") private String oldCode; - // TODO @芋艿:oldMobile 应该不用传递 - - @Schema(description = "原手机号",requiredMode = Schema.RequiredMode.REQUIRED,example = "15823654487") - @NotBlank(message = "手机号不能为空") - @Length(min = 8, max = 11, message = "手机号码长度为 8-11 位") - @Mobile - private String oldMobile; - } diff --git a/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/convert/auth/AuthConvert.java b/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/convert/auth/AuthConvert.java index 755d71a21..359e3b904 100644 --- a/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/convert/auth/AuthConvert.java +++ b/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/convert/auth/AuthConvert.java @@ -5,6 +5,7 @@ import cn.iocoder.yudao.module.member.controller.app.social.vo.AppSocialUserUnbi import cn.iocoder.yudao.module.system.api.oauth2.dto.OAuth2AccessTokenRespDTO; import cn.iocoder.yudao.module.system.api.sms.dto.code.SmsCodeSendReqDTO; import cn.iocoder.yudao.module.system.api.sms.dto.code.SmsCodeUseReqDTO; +import cn.iocoder.yudao.module.system.api.sms.dto.code.SmsCodeValidateReqDTO; import cn.iocoder.yudao.module.system.api.social.dto.SocialUserBindReqDTO; import cn.iocoder.yudao.module.system.api.social.dto.SocialUserUnbindReqDTO; import cn.iocoder.yudao.module.system.enums.sms.SmsSceneEnum; @@ -25,4 +26,6 @@ public interface AuthConvert { AppAuthLoginRespVO convert(OAuth2AccessTokenRespDTO bean); + SmsCodeValidateReqDTO convert(AppAuthSmsValidateReqVO bean); + } diff --git a/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/service/auth/MemberAuthService.java b/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/service/auth/MemberAuthService.java index 6990fba2e..17e231da8 100644 --- a/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/service/auth/MemberAuthService.java +++ b/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/service/auth/MemberAuthService.java @@ -82,6 +82,14 @@ public interface MemberAuthService { */ void sendSmsCode(Long userId, AppAuthSmsSendReqVO reqVO); + /** + * 校验短信验证码是否正确 + * + * @param userId 用户编号 + * @param reqVO 校验信息 + */ + void validateSmsCode(Long userId, AppAuthSmsValidateReqVO reqVO); + /** * 刷新访问令牌 * diff --git a/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/service/auth/MemberAuthServiceImpl.java b/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/service/auth/MemberAuthServiceImpl.java index 40659e8fc..a481b2dc6 100644 --- a/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/service/auth/MemberAuthServiceImpl.java +++ b/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/service/auth/MemberAuthServiceImpl.java @@ -236,13 +236,27 @@ public class MemberAuthServiceImpl implements MemberAuthService { @Override public void sendSmsCode(Long userId, AppAuthSmsSendReqVO reqVO) { - // TODO 要根据不同的场景,校验是否有用户 + // 如果是修改手机场景,需要校验新手机号是否已经注册,说明不能使用该手机了 + if (Objects.equals(reqVO.getScene(), SmsSceneEnum.MEMBER_UPDATE_MOBILE.getScene())) { + MemberUserDO user = userMapper.selectByMobile(reqVO.getMobile()); + if (user != null && !Objects.equals(user.getId(), userId)) { + throw exception(AUTH_MOBILE_USED); + } + } + + // 执行发送 smsCodeApi.sendSmsCode(AuthConvert.INSTANCE.convert(reqVO).setCreateIp(getClientIP())); } + @Override + public void validateSmsCode(Long userId, AppAuthSmsValidateReqVO reqVO) { + smsCodeApi.validateSmsCode(AuthConvert.INSTANCE.convert(reqVO)); + } + @Override public AppAuthLoginRespVO refreshToken(String refreshToken) { - OAuth2AccessTokenRespDTO accessTokenDO = oauth2TokenApi.refreshAccessToken(refreshToken, OAuth2ClientConstants.CLIENT_ID_DEFAULT); + OAuth2AccessTokenRespDTO accessTokenDO = oauth2TokenApi.refreshAccessToken(refreshToken, + OAuth2ClientConstants.CLIENT_ID_DEFAULT); return AuthConvert.INSTANCE.convert(accessTokenDO); } diff --git a/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/service/user/MemberUserServiceImpl.java b/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/service/user/MemberUserServiceImpl.java index c7914512c..9d551e23a 100644 --- a/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/service/user/MemberUserServiceImpl.java +++ b/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/service/user/MemberUserServiceImpl.java @@ -29,8 +29,7 @@ import java.util.List; 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.member.enums.ErrorCodeConstants.USER_NOT_EXISTS; -import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.USER_MOBILE_EXISTS; +import static cn.iocoder.yudao.module.member.enums.ErrorCodeConstants.*; /** * 会员 User Service 实现类 @@ -113,11 +112,12 @@ public class MemberUserServiceImpl implements MemberUserService { @Transactional(rollbackFor = Exception.class) public void updateUserMobile(Long userId, AppUserUpdateMobileReqVO reqVO) { // 检测用户是否存在 - validateUserExists(userId); - // TODO 芋艿:oldMobile 应该不用传递 + MemberUserDO user = validateUserExists(userId); + // 校验新手机是否已经被绑定 + validateMobileUnique(null, reqVO.getMobile()); // 校验旧手机和旧验证码 - smsCodeApi.useSmsCode(new SmsCodeUseReqDTO().setMobile(reqVO.getOldMobile()).setCode(reqVO.getOldCode()) + smsCodeApi.useSmsCode(new SmsCodeUseReqDTO().setMobile(user.getMobile()).setCode(reqVO.getOldCode()) .setScene(SmsSceneEnum.MEMBER_UPDATE_MOBILE.getScene()).setUsedIp(getClientIP())); // 使用新验证码 smsCodeApi.useSmsCode(new SmsCodeUseReqDTO().setMobile(reqVO.getMobile()).setCode(reqVO.getCode()) @@ -177,10 +177,10 @@ public class MemberUserServiceImpl implements MemberUserService { } // 如果 id 为空,说明不用比较是否为相同 id 的用户 if (id == null) { - throw exception(USER_MOBILE_EXISTS); + throw exception(USER_MOBILE_USED); } if (!user.getId().equals(id)) { - throw exception(USER_MOBILE_EXISTS); + throw exception(USER_MOBILE_USED); } } diff --git a/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/enums/sms/SmsSceneEnum.java b/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/enums/sms/SmsSceneEnum.java index 9a674c89f..fb1fc574a 100644 --- a/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/enums/sms/SmsSceneEnum.java +++ b/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/enums/sms/SmsSceneEnum.java @@ -17,8 +17,8 @@ import java.util.Arrays; public enum SmsSceneEnum implements IntArrayValuable { MEMBER_LOGIN(1, "user-sms-login", "会员用户 - 手机号登陆"), - MEMBER_UPDATE_MOBILE(2, "user-sms-reset-password", "会员用户 - 修改手机"), - MEMBER_FORGET_PASSWORD(3, "user-sms-update-mobile", "会员用户 - 忘记密码"), + MEMBER_UPDATE_MOBILE(2, "user-sms-update-mobile", "会员用户 - 修改手机"), + MEMBER_FORGET_PASSWORD(3, "user-sms-forget-password", "会员用户 - 忘记密码"), ADMIN_MEMBER_LOGIN(21, "admin-sms-login", "后台用户 - 手机号登录");