Commit 87e5b2bed13cc6558e538739914ffb81dc82fcc4
1 parent
41533315
1. 会员用户的修改手机 API 的优化
Showing
10 changed files
with
90 additions
and
29 deletions
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 { |
| 12 | 12 | // ========== 用户相关 1004001000============ |
| 13 | 13 | ErrorCode USER_NOT_EXISTS = new ErrorCode(1004001000, "用户不存在"); |
| 14 | 14 | ErrorCode USER_PASSWORD_FAILED = new ErrorCode(1004001001, "密码校验失败"); |
| 15 | + ErrorCode USER_MOBILE_USED = new ErrorCode(1004001002, "修改手机失败,该手机号({})已经被使用"); | |
| 15 | 16 | |
| 16 | 17 | // ========== AUTH 模块 1004003000 ========== |
| 17 | 18 | ErrorCode AUTH_LOGIN_BAD_CREDENTIALS = new ErrorCode(1004003000, "登录失败,账号密码不正确"); |
| ... | ... | @@ -19,6 +20,7 @@ public interface ErrorCodeConstants { |
| 19 | 20 | ErrorCode AUTH_TOKEN_EXPIRED = new ErrorCode(1004003004, "Token 已经过期"); |
| 20 | 21 | ErrorCode AUTH_THIRD_LOGIN_NOT_BIND = new ErrorCode(1004003005, "未绑定账号,需要进行绑定"); |
| 21 | 22 | ErrorCode AUTH_WEIXIN_MINI_APP_PHONE_CODE_ERROR = new ErrorCode(1004003006, "获得手机号失败"); |
| 23 | + ErrorCode AUTH_MOBILE_USED = new ErrorCode(1004003007, "手机号已经被使用"); | |
| 22 | 24 | |
| 23 | 25 | // ========== 用户收件地址 1004004000 ========== |
| 24 | 26 | ErrorCode ADDRESS_NOT_EXISTS = new ErrorCode(1004004000, "用户收件地址不存在"); | ... | ... |
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 { |
| 77 | 77 | return success(true); |
| 78 | 78 | } |
| 79 | 79 | |
| 80 | + @PostMapping("/validate-sms-code") | |
| 81 | + @Operation(summary = "校验手机验证码") | |
| 82 | + public CommonResult<Boolean> validateSmsCode(@RequestBody @Valid AppAuthSmsValidateReqVO reqVO) { | |
| 83 | + authService.validateSmsCode(getLoginUserId(), reqVO); | |
| 84 | + return success(true); | |
| 85 | + } | |
| 86 | + | |
| 80 | 87 | @PostMapping("/reset-password") |
| 81 | 88 | @Operation(summary = "重置密码", description = "用户忘记密码时使用") |
| 82 | 89 | @PreAuthenticated | ... | ... |
yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/app/auth/vo/AppAuthSmsValidateReqVO.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.member.controller.app.auth.vo; | |
| 2 | + | |
| 3 | +import cn.iocoder.yudao.framework.common.validation.InEnum; | |
| 4 | +import cn.iocoder.yudao.framework.common.validation.Mobile; | |
| 5 | +import cn.iocoder.yudao.module.system.enums.sms.SmsSceneEnum; | |
| 6 | +import io.swagger.v3.oas.annotations.media.Schema; | |
| 7 | +import lombok.Data; | |
| 8 | +import lombok.experimental.Accessors; | |
| 9 | +import org.hibernate.validator.constraints.Length; | |
| 10 | + | |
| 11 | +import javax.validation.constraints.NotEmpty; | |
| 12 | +import javax.validation.constraints.NotNull; | |
| 13 | +import javax.validation.constraints.Pattern; | |
| 14 | + | |
| 15 | +@Schema(description = "用户 APP - 校验手机验证码 Request VO") | |
| 16 | +@Data | |
| 17 | +@Accessors(chain = true) | |
| 18 | +public class AppAuthSmsValidateReqVO { | |
| 19 | + | |
| 20 | + @Schema(description = "手机号", example = "15601691234") | |
| 21 | + @Mobile | |
| 22 | + private String mobile; | |
| 23 | + | |
| 24 | + @Schema(description = "发送场景,对应 SmsSceneEnum 枚举", example = "1") | |
| 25 | + @NotNull(message = "发送场景不能为空") | |
| 26 | + @InEnum(SmsSceneEnum.class) | |
| 27 | + private Integer scene; | |
| 28 | + | |
| 29 | + @Schema(description = "手机验证码", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") | |
| 30 | + @NotEmpty(message = "手机验证码不能为空") | |
| 31 | + @Length(min = 4, max = 6, message = "手机验证码长度为 4-6 位") | |
| 32 | + @Pattern(regexp = "^[0-9]+$", message = "手机验证码必须都是数字") | |
| 33 | + private String code; | |
| 34 | + | |
| 35 | +} | ... | ... |
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 { |
| 30 | 30 | @Resource |
| 31 | 31 | private MemberUserService userService; |
| 32 | 32 | |
| 33 | - @PutMapping("/update") | |
| 34 | - @Operation(summary = "修改基本信息") | |
| 35 | - @PreAuthenticated | |
| 36 | - public CommonResult<Boolean> updateUser(@RequestBody @Valid AppMemberUserUpdateReqVO reqVO) { | |
| 37 | - userService.updateUser(getLoginUserId(), reqVO); | |
| 38 | - return success(true); | |
| 39 | - } | |
| 40 | - | |
| 41 | 33 | @GetMapping("/get") |
| 42 | 34 | @Operation(summary = "获得基本信息") |
| 43 | 35 | @PreAuthenticated |
| ... | ... | @@ -46,10 +38,18 @@ public class AppMemberUserController { |
| 46 | 38 | return success(MemberUserConvert.INSTANCE.convert(user)); |
| 47 | 39 | } |
| 48 | 40 | |
| 49 | - @PostMapping("/update-mobile") | |
| 41 | + @PutMapping("/update") | |
| 42 | + @Operation(summary = "修改基本信息") | |
| 43 | + @PreAuthenticated | |
| 44 | + public CommonResult<Boolean> updateUser(@RequestBody @Valid AppMemberUserUpdateReqVO reqVO) { | |
| 45 | + userService.updateUser(getLoginUserId(), reqVO); | |
| 46 | + return success(true); | |
| 47 | + } | |
| 48 | + | |
| 49 | + @PutMapping("/update-mobile") | |
| 50 | 50 | @Operation(summary = "修改用户手机") |
| 51 | 51 | @PreAuthenticated |
| 52 | - public CommonResult<Boolean> updateMobile(@RequestBody @Valid AppUserUpdateMobileReqVO reqVO) { | |
| 52 | + public CommonResult<Boolean> updateUserMobile(@RequestBody @Valid AppUserUpdateMobileReqVO reqVO) { | |
| 53 | 53 | userService.updateUserMobile(getLoginUserId(), reqVO); |
| 54 | 54 | return success(true); |
| 55 | 55 | } | ... | ... |
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 { |
| 37 | 37 | @Pattern(regexp = "^[0-9]+$", message = "手机验证码必须都是数字") |
| 38 | 38 | private String oldCode; |
| 39 | 39 | |
| 40 | - // TODO @芋艿:oldMobile 应该不用传递 | |
| 41 | - | |
| 42 | - @Schema(description = "原手机号",requiredMode = Schema.RequiredMode.REQUIRED,example = "15823654487") | |
| 43 | - @NotBlank(message = "手机号不能为空") | |
| 44 | - @Length(min = 8, max = 11, message = "手机号码长度为 8-11 位") | |
| 45 | - @Mobile | |
| 46 | - private String oldMobile; | |
| 47 | - | |
| 48 | 40 | } | ... | ... |
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 |
| 5 | 5 | import cn.iocoder.yudao.module.system.api.oauth2.dto.OAuth2AccessTokenRespDTO; |
| 6 | 6 | import cn.iocoder.yudao.module.system.api.sms.dto.code.SmsCodeSendReqDTO; |
| 7 | 7 | import cn.iocoder.yudao.module.system.api.sms.dto.code.SmsCodeUseReqDTO; |
| 8 | +import cn.iocoder.yudao.module.system.api.sms.dto.code.SmsCodeValidateReqDTO; | |
| 8 | 9 | import cn.iocoder.yudao.module.system.api.social.dto.SocialUserBindReqDTO; |
| 9 | 10 | import cn.iocoder.yudao.module.system.api.social.dto.SocialUserUnbindReqDTO; |
| 10 | 11 | import cn.iocoder.yudao.module.system.enums.sms.SmsSceneEnum; |
| ... | ... | @@ -25,4 +26,6 @@ public interface AuthConvert { |
| 25 | 26 | |
| 26 | 27 | AppAuthLoginRespVO convert(OAuth2AccessTokenRespDTO bean); |
| 27 | 28 | |
| 29 | + SmsCodeValidateReqDTO convert(AppAuthSmsValidateReqVO bean); | |
| 30 | + | |
| 28 | 31 | } | ... | ... |
yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/service/auth/MemberAuthService.java
| ... | ... | @@ -83,6 +83,14 @@ public interface MemberAuthService { |
| 83 | 83 | void sendSmsCode(Long userId, AppAuthSmsSendReqVO reqVO); |
| 84 | 84 | |
| 85 | 85 | /** |
| 86 | + * 校验短信验证码是否正确 | |
| 87 | + * | |
| 88 | + * @param userId 用户编号 | |
| 89 | + * @param reqVO 校验信息 | |
| 90 | + */ | |
| 91 | + void validateSmsCode(Long userId, AppAuthSmsValidateReqVO reqVO); | |
| 92 | + | |
| 93 | + /** | |
| 86 | 94 | * 刷新访问令牌 |
| 87 | 95 | * |
| 88 | 96 | * @param refreshToken 刷新令牌 | ... | ... |
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 { |
| 236 | 236 | |
| 237 | 237 | @Override |
| 238 | 238 | public void sendSmsCode(Long userId, AppAuthSmsSendReqVO reqVO) { |
| 239 | - // TODO 要根据不同的场景,校验是否有用户 | |
| 239 | + // 如果是修改手机场景,需要校验新手机号是否已经注册,说明不能使用该手机了 | |
| 240 | + if (Objects.equals(reqVO.getScene(), SmsSceneEnum.MEMBER_UPDATE_MOBILE.getScene())) { | |
| 241 | + MemberUserDO user = userMapper.selectByMobile(reqVO.getMobile()); | |
| 242 | + if (user != null && !Objects.equals(user.getId(), userId)) { | |
| 243 | + throw exception(AUTH_MOBILE_USED); | |
| 244 | + } | |
| 245 | + } | |
| 246 | + | |
| 247 | + // 执行发送 | |
| 240 | 248 | smsCodeApi.sendSmsCode(AuthConvert.INSTANCE.convert(reqVO).setCreateIp(getClientIP())); |
| 241 | 249 | } |
| 242 | 250 | |
| 243 | 251 | @Override |
| 252 | + public void validateSmsCode(Long userId, AppAuthSmsValidateReqVO reqVO) { | |
| 253 | + smsCodeApi.validateSmsCode(AuthConvert.INSTANCE.convert(reqVO)); | |
| 254 | + } | |
| 255 | + | |
| 256 | + @Override | |
| 244 | 257 | public AppAuthLoginRespVO refreshToken(String refreshToken) { |
| 245 | - OAuth2AccessTokenRespDTO accessTokenDO = oauth2TokenApi.refreshAccessToken(refreshToken, OAuth2ClientConstants.CLIENT_ID_DEFAULT); | |
| 258 | + OAuth2AccessTokenRespDTO accessTokenDO = oauth2TokenApi.refreshAccessToken(refreshToken, | |
| 259 | + OAuth2ClientConstants.CLIENT_ID_DEFAULT); | |
| 246 | 260 | return AuthConvert.INSTANCE.convert(accessTokenDO); |
| 247 | 261 | } |
| 248 | 262 | ... | ... |
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; |
| 29 | 29 | |
| 30 | 30 | import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; |
| 31 | 31 | import static cn.iocoder.yudao.framework.common.util.servlet.ServletUtils.getClientIP; |
| 32 | -import static cn.iocoder.yudao.module.member.enums.ErrorCodeConstants.USER_NOT_EXISTS; | |
| 33 | -import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.USER_MOBILE_EXISTS; | |
| 32 | +import static cn.iocoder.yudao.module.member.enums.ErrorCodeConstants.*; | |
| 34 | 33 | |
| 35 | 34 | /** |
| 36 | 35 | * 会员 User Service 实现类 |
| ... | ... | @@ -113,11 +112,12 @@ public class MemberUserServiceImpl implements MemberUserService { |
| 113 | 112 | @Transactional(rollbackFor = Exception.class) |
| 114 | 113 | public void updateUserMobile(Long userId, AppUserUpdateMobileReqVO reqVO) { |
| 115 | 114 | // 检测用户是否存在 |
| 116 | - validateUserExists(userId); | |
| 117 | - // TODO 芋艿:oldMobile 应该不用传递 | |
| 115 | + MemberUserDO user = validateUserExists(userId); | |
| 116 | + // 校验新手机是否已经被绑定 | |
| 117 | + validateMobileUnique(null, reqVO.getMobile()); | |
| 118 | 118 | |
| 119 | 119 | // 校验旧手机和旧验证码 |
| 120 | - smsCodeApi.useSmsCode(new SmsCodeUseReqDTO().setMobile(reqVO.getOldMobile()).setCode(reqVO.getOldCode()) | |
| 120 | + smsCodeApi.useSmsCode(new SmsCodeUseReqDTO().setMobile(user.getMobile()).setCode(reqVO.getOldCode()) | |
| 121 | 121 | .setScene(SmsSceneEnum.MEMBER_UPDATE_MOBILE.getScene()).setUsedIp(getClientIP())); |
| 122 | 122 | // 使用新验证码 |
| 123 | 123 | smsCodeApi.useSmsCode(new SmsCodeUseReqDTO().setMobile(reqVO.getMobile()).setCode(reqVO.getCode()) |
| ... | ... | @@ -177,10 +177,10 @@ public class MemberUserServiceImpl implements MemberUserService { |
| 177 | 177 | } |
| 178 | 178 | // 如果 id 为空,说明不用比较是否为相同 id 的用户 |
| 179 | 179 | if (id == null) { |
| 180 | - throw exception(USER_MOBILE_EXISTS); | |
| 180 | + throw exception(USER_MOBILE_USED); | |
| 181 | 181 | } |
| 182 | 182 | if (!user.getId().equals(id)) { |
| 183 | - throw exception(USER_MOBILE_EXISTS); | |
| 183 | + throw exception(USER_MOBILE_USED); | |
| 184 | 184 | } |
| 185 | 185 | } |
| 186 | 186 | ... | ... |
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; |
| 17 | 17 | public enum SmsSceneEnum implements IntArrayValuable { |
| 18 | 18 | |
| 19 | 19 | MEMBER_LOGIN(1, "user-sms-login", "会员用户 - 手机号登陆"), |
| 20 | - MEMBER_UPDATE_MOBILE(2, "user-sms-reset-password", "会员用户 - 修改手机"), | |
| 21 | - MEMBER_FORGET_PASSWORD(3, "user-sms-update-mobile", "会员用户 - 忘记密码"), | |
| 20 | + MEMBER_UPDATE_MOBILE(2, "user-sms-update-mobile", "会员用户 - 修改手机"), | |
| 21 | + MEMBER_FORGET_PASSWORD(3, "user-sms-forget-password", "会员用户 - 忘记密码"), | |
| 22 | 22 | |
| 23 | 23 | ADMIN_MEMBER_LOGIN(21, "admin-sms-login", "后台用户 - 手机号登录"); |
| 24 | 24 | ... | ... |