Commit 8e0569ee544b26cc6944c7eab6bb92d82bca57f6
1 parent
c84e19e1
update 新增接口:修改手机,修改密码,忘记密码
Showing
19 changed files
with
696 additions
and
18 deletions
yudao-user-server/pom.xml
| @@ -91,6 +91,13 @@ | @@ -91,6 +91,13 @@ | ||
| 91 | <scope>test</scope> | 91 | <scope>test</scope> |
| 92 | </dependency> | 92 | </dependency> |
| 93 | 93 | ||
| 94 | + <!--单元测试相关--> | ||
| 95 | + <dependency> | ||
| 96 | + <groupId>junit</groupId> | ||
| 97 | + <artifactId>junit</artifactId> | ||
| 98 | + <scope>test</scope> | ||
| 99 | + </dependency> | ||
| 100 | + | ||
| 94 | <!-- 工具类相关 --> | 101 | <!-- 工具类相关 --> |
| 95 | 102 | ||
| 96 | </dependencies> | 103 | </dependencies> |
yudao-user-server/src/main/java/cn/iocoder/yudao/userserver/modules/member/controller/user/SysUserProfileController.java
| @@ -5,6 +5,9 @@ import cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil; | @@ -5,6 +5,9 @@ import cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil; | ||
| 5 | import cn.iocoder.yudao.framework.common.pojo.CommonResult; | 5 | import cn.iocoder.yudao.framework.common.pojo.CommonResult; |
| 6 | import cn.iocoder.yudao.framework.security.core.annotations.PreAuthenticated; | 6 | import cn.iocoder.yudao.framework.security.core.annotations.PreAuthenticated; |
| 7 | import cn.iocoder.yudao.userserver.modules.member.service.user.MbrUserService; | 7 | import cn.iocoder.yudao.userserver.modules.member.service.user.MbrUserService; |
| 8 | +import cn.iocoder.yudao.userserver.modules.member.controller.user.vo.MbrUserUpdateMobileReqVO; | ||
| 9 | +import cn.iocoder.yudao.userserver.modules.system.enums.sms.SysSmsSceneEnum; | ||
| 10 | +import cn.iocoder.yudao.userserver.modules.system.service.sms.SysSmsCodeService; | ||
| 8 | import io.swagger.annotations.Api; | 11 | import io.swagger.annotations.Api; |
| 9 | import io.swagger.annotations.ApiOperation; | 12 | import io.swagger.annotations.ApiOperation; |
| 10 | import lombok.extern.slf4j.Slf4j; | 13 | import lombok.extern.slf4j.Slf4j; |
| @@ -13,10 +16,12 @@ import org.springframework.web.bind.annotation.*; | @@ -13,10 +16,12 @@ import org.springframework.web.bind.annotation.*; | ||
| 13 | import org.springframework.web.multipart.MultipartFile; | 16 | import org.springframework.web.multipart.MultipartFile; |
| 14 | 17 | ||
| 15 | import javax.annotation.Resource; | 18 | import javax.annotation.Resource; |
| 19 | +import javax.validation.Valid; | ||
| 16 | 20 | ||
| 17 | import java.io.IOException; | 21 | import java.io.IOException; |
| 18 | 22 | ||
| 19 | import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; | 23 | import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; |
| 24 | +import static cn.iocoder.yudao.framework.common.util.servlet.ServletUtils.getClientIP; | ||
| 20 | import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId; | 25 | import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId; |
| 21 | import static cn.iocoder.yudao.userserver.modules.member.enums.MbrErrorCodeConstants.FILE_IS_EMPTY; | 26 | import static cn.iocoder.yudao.userserver.modules.member.enums.MbrErrorCodeConstants.FILE_IS_EMPTY; |
| 22 | 27 | ||
| @@ -30,6 +35,9 @@ public class SysUserProfileController { | @@ -30,6 +35,9 @@ public class SysUserProfileController { | ||
| 30 | @Resource | 35 | @Resource |
| 31 | private MbrUserService userService; | 36 | private MbrUserService userService; |
| 32 | 37 | ||
| 38 | + @Resource | ||
| 39 | + private SysSmsCodeService smsCodeService; | ||
| 40 | + | ||
| 33 | @PutMapping("/update-nickname") | 41 | @PutMapping("/update-nickname") |
| 34 | @ApiOperation("修改用户昵称") | 42 | @ApiOperation("修改用户昵称") |
| 35 | @PreAuthenticated | 43 | @PreAuthenticated |
| @@ -56,5 +64,17 @@ public class SysUserProfileController { | @@ -56,5 +64,17 @@ public class SysUserProfileController { | ||
| 56 | return success(userService.getUserInfo(getLoginUserId())); | 64 | return success(userService.getUserInfo(getLoginUserId())); |
| 57 | } | 65 | } |
| 58 | 66 | ||
| 67 | + | ||
| 68 | + @PostMapping("/update-mobile") | ||
| 69 | + @ApiOperation(value = "修改用户手机") | ||
| 70 | + @PreAuthenticated | ||
| 71 | + public CommonResult<Boolean> updateMobile(@RequestBody @Valid MbrUserUpdateMobileReqVO reqVO) { | ||
| 72 | + // 校验验证码 | ||
| 73 | + smsCodeService.useSmsCode(reqVO.getMobile(),SysSmsSceneEnum.CHANGE_MOBILE_BY_SMS.getScene(), reqVO.getCode(),getClientIP()); | ||
| 74 | + | ||
| 75 | + userService.updateMobile(getLoginUserId(), reqVO); | ||
| 76 | + return success(true); | ||
| 77 | + } | ||
| 78 | + | ||
| 59 | } | 79 | } |
| 60 | 80 |
yudao-user-server/src/main/java/cn/iocoder/yudao/userserver/modules/member/controller/user/vo/MbrUserUpdateMobileReqVO.java
0 → 100644
| 1 | +package cn.iocoder.yudao.userserver.modules.member.controller.user.vo; | ||
| 2 | + | ||
| 3 | +import io.swagger.annotations.ApiModel; | ||
| 4 | +import io.swagger.annotations.ApiModelProperty; | ||
| 5 | +import lombok.AllArgsConstructor; | ||
| 6 | +import lombok.Builder; | ||
| 7 | +import lombok.Data; | ||
| 8 | +import lombok.NoArgsConstructor; | ||
| 9 | +import org.hibernate.validator.constraints.Length; | ||
| 10 | + | ||
| 11 | +import javax.validation.constraints.NotBlank; | ||
| 12 | +import javax.validation.constraints.NotEmpty; | ||
| 13 | +import javax.validation.constraints.Pattern; | ||
| 14 | + | ||
| 15 | +@ApiModel("修改手机 Request VO") | ||
| 16 | +@Data | ||
| 17 | +@NoArgsConstructor | ||
| 18 | +@AllArgsConstructor | ||
| 19 | +@Builder | ||
| 20 | +public class MbrUserUpdateMobileReqVO { | ||
| 21 | + | ||
| 22 | + @ApiModelProperty(value = "手机验证码", required = true, example = "1024") | ||
| 23 | + @NotEmpty(message = "手机验证码不能为空") | ||
| 24 | + @Length(min = 4, max = 6, message = "手机验证码长度为 4-6 位") | ||
| 25 | + @Pattern(regexp = "^[0-9]+$", message = "手机验证码必须都是数字") | ||
| 26 | + private String code; | ||
| 27 | + | ||
| 28 | + | ||
| 29 | + @ApiModelProperty(value = "手机号",required = true,example = "15823654487") | ||
| 30 | + @NotBlank(message = "手机号不能为空") | ||
| 31 | + @Length(min = 8, max = 11, message = "手机号码长度为 8-11 位") | ||
| 32 | + @Pattern(regexp = "^1[3-9]\\d{9}$", message = "手机号格式错误") | ||
| 33 | + private String mobile; | ||
| 34 | + | ||
| 35 | +} |
yudao-user-server/src/main/java/cn/iocoder/yudao/userserver/modules/member/service/user/MbrUserService.java
| @@ -3,6 +3,7 @@ package cn.iocoder.yudao.userserver.modules.member.service.user; | @@ -3,6 +3,7 @@ package cn.iocoder.yudao.userserver.modules.member.service.user; | ||
| 3 | import cn.iocoder.yudao.coreservice.modules.member.dal.dataobject.user.MbrUserDO; | 3 | import cn.iocoder.yudao.coreservice.modules.member.dal.dataobject.user.MbrUserDO; |
| 4 | import cn.iocoder.yudao.userserver.modules.member.controller.user.vo.MbrUserInfoRespVO; | 4 | import cn.iocoder.yudao.userserver.modules.member.controller.user.vo.MbrUserInfoRespVO; |
| 5 | import cn.iocoder.yudao.framework.common.validation.Mobile; | 5 | import cn.iocoder.yudao.framework.common.validation.Mobile; |
| 6 | +import cn.iocoder.yudao.userserver.modules.member.controller.user.vo.MbrUserUpdateMobileReqVO; | ||
| 6 | 7 | ||
| 7 | import java.io.InputStream; | 8 | import java.io.InputStream; |
| 8 | 9 | ||
| @@ -69,4 +70,11 @@ public interface MbrUserService { | @@ -69,4 +70,11 @@ public interface MbrUserService { | ||
| 69 | */ | 70 | */ |
| 70 | MbrUserInfoRespVO getUserInfo(Long userId); | 71 | MbrUserInfoRespVO getUserInfo(Long userId); |
| 71 | 72 | ||
| 73 | + /** | ||
| 74 | + * 修改手机 | ||
| 75 | + * @param userId 用户id | ||
| 76 | + * @param reqVO 请求实体 | ||
| 77 | + */ | ||
| 78 | + void updateMobile(Long userId, MbrUserUpdateMobileReqVO reqVO); | ||
| 79 | + | ||
| 72 | } | 80 | } |
yudao-user-server/src/main/java/cn/iocoder/yudao/userserver/modules/member/service/user/impl/MbrUserServiceImpl.java
| @@ -6,8 +6,10 @@ import cn.iocoder.yudao.coreservice.modules.infra.service.file.InfFileCoreServic | @@ -6,8 +6,10 @@ import cn.iocoder.yudao.coreservice.modules.infra.service.file.InfFileCoreServic | ||
| 6 | import cn.iocoder.yudao.coreservice.modules.member.dal.dataobject.user.MbrUserDO; | 6 | import cn.iocoder.yudao.coreservice.modules.member.dal.dataobject.user.MbrUserDO; |
| 7 | import cn.iocoder.yudao.userserver.modules.member.controller.user.vo.MbrUserInfoRespVO; | 7 | import cn.iocoder.yudao.userserver.modules.member.controller.user.vo.MbrUserInfoRespVO; |
| 8 | import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; | 8 | import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; |
| 9 | +import cn.iocoder.yudao.userserver.modules.member.controller.user.vo.MbrUserUpdateMobileReqVO; | ||
| 9 | import cn.iocoder.yudao.userserver.modules.member.dal.mysql.user.MbrUserMapper; | 10 | import cn.iocoder.yudao.userserver.modules.member.dal.mysql.user.MbrUserMapper; |
| 10 | import cn.iocoder.yudao.userserver.modules.member.service.user.MbrUserService; | 11 | import cn.iocoder.yudao.userserver.modules.member.service.user.MbrUserService; |
| 12 | +import cn.iocoder.yudao.userserver.modules.system.service.auth.SysAuthService; | ||
| 11 | import com.google.common.annotations.VisibleForTesting; | 13 | import com.google.common.annotations.VisibleForTesting; |
| 12 | import lombok.extern.slf4j.Slf4j; | 14 | import lombok.extern.slf4j.Slf4j; |
| 13 | import org.springframework.security.crypto.password.PasswordEncoder; | 15 | import org.springframework.security.crypto.password.PasswordEncoder; |
| @@ -40,6 +42,9 @@ public class MbrUserServiceImpl implements MbrUserService { | @@ -40,6 +42,9 @@ public class MbrUserServiceImpl implements MbrUserService { | ||
| 40 | @Resource | 42 | @Resource |
| 41 | private PasswordEncoder passwordEncoder; | 43 | private PasswordEncoder passwordEncoder; |
| 42 | 44 | ||
| 45 | + @Resource | ||
| 46 | + private SysAuthService sysAuthService; | ||
| 47 | + | ||
| 43 | @Override | 48 | @Override |
| 44 | public MbrUserDO getUserByMobile(String mobile) { | 49 | public MbrUserDO getUserByMobile(String mobile) { |
| 45 | return userMapper.selectByMobile(mobile); | 50 | return userMapper.selectByMobile(mobile); |
| @@ -116,6 +121,17 @@ public class MbrUserServiceImpl implements MbrUserService { | @@ -116,6 +121,17 @@ public class MbrUserServiceImpl implements MbrUserService { | ||
| 116 | return userResp; | 121 | return userResp; |
| 117 | } | 122 | } |
| 118 | 123 | ||
| 124 | + @Override | ||
| 125 | + public void updateMobile(Long userId, MbrUserUpdateMobileReqVO reqVO) { | ||
| 126 | + // 检测用户是否存在 | ||
| 127 | + MbrUserDO userDO = checkUserExists(userId); | ||
| 128 | + // 检测手机与验证码是否匹配 | ||
| 129 | + sysAuthService.checkIfMobileMatchCodeAndDeleteCode(userDO.getMobile(),reqVO.getCode()); | ||
| 130 | + // 更新用户手机 | ||
| 131 | + userDO.setMobile(reqVO.getMobile()); | ||
| 132 | + userMapper.updateById(userDO); | ||
| 133 | + } | ||
| 134 | + | ||
| 119 | @VisibleForTesting | 135 | @VisibleForTesting |
| 120 | public MbrUserDO checkUserExists(Long id) { | 136 | public MbrUserDO checkUserExists(Long id) { |
| 121 | if (id == null) { | 137 | if (id == null) { |
yudao-user-server/src/main/java/cn/iocoder/yudao/userserver/modules/system/controller/auth/SysAuthController.java
| @@ -3,7 +3,9 @@ package cn.iocoder.yudao.userserver.modules.system.controller.auth; | @@ -3,7 +3,9 @@ package cn.iocoder.yudao.userserver.modules.system.controller.auth; | ||
| 3 | import cn.iocoder.yudao.coreservice.modules.system.service.social.SysSocialService; | 3 | import cn.iocoder.yudao.coreservice.modules.system.service.social.SysSocialService; |
| 4 | import cn.iocoder.yudao.framework.common.enums.UserTypeEnum; | 4 | import cn.iocoder.yudao.framework.common.enums.UserTypeEnum; |
| 5 | import cn.iocoder.yudao.framework.common.pojo.CommonResult; | 5 | import cn.iocoder.yudao.framework.common.pojo.CommonResult; |
| 6 | +import cn.iocoder.yudao.framework.security.core.annotations.PreAuthenticated; | ||
| 6 | import cn.iocoder.yudao.userserver.modules.system.controller.auth.vo.*; | 7 | import cn.iocoder.yudao.userserver.modules.system.controller.auth.vo.*; |
| 8 | +import cn.iocoder.yudao.userserver.modules.system.enums.sms.SysSmsSceneEnum; | ||
| 7 | import cn.iocoder.yudao.userserver.modules.system.service.auth.SysAuthService; | 9 | import cn.iocoder.yudao.userserver.modules.system.service.auth.SysAuthService; |
| 8 | import cn.iocoder.yudao.userserver.modules.system.service.sms.SysSmsCodeService; | 10 | import cn.iocoder.yudao.userserver.modules.system.service.sms.SysSmsCodeService; |
| 9 | import com.alibaba.fastjson.JSON; | 11 | import com.alibaba.fastjson.JSON; |
| @@ -56,16 +58,47 @@ public class SysAuthController { | @@ -56,16 +58,47 @@ public class SysAuthController { | ||
| 56 | } | 58 | } |
| 57 | 59 | ||
| 58 | @PostMapping("/send-sms-code") | 60 | @PostMapping("/send-sms-code") |
| 59 | - @ApiOperation("发送手机验证码") | 61 | + @ApiOperation(value = "发送手机验证码",notes = "不检测该手机号是否已被注册") |
| 60 | public CommonResult<Boolean> sendSmsCode(@RequestBody @Valid SysAuthSendSmsReqVO reqVO) { | 62 | public CommonResult<Boolean> sendSmsCode(@RequestBody @Valid SysAuthSendSmsReqVO reqVO) { |
| 61 | smsCodeService.sendSmsCode(reqVO.getMobile(), reqVO.getScene(), getClientIP()); | 63 | smsCodeService.sendSmsCode(reqVO.getMobile(), reqVO.getScene(), getClientIP()); |
| 62 | return success(true); | 64 | return success(true); |
| 63 | } | 65 | } |
| 64 | 66 | ||
| 67 | + @PostMapping("/send-sms-new-code") | ||
| 68 | + @ApiOperation(value = "发送手机验证码",notes = "检测该手机号是否已被注册,用于修改手机时使用") | ||
| 69 | + public CommonResult<Boolean> sendSmsNewCode(@RequestBody @Valid SysAuthSendSmsReqVO reqVO) { | ||
| 70 | + smsCodeService.sendSmsNewCode(reqVO); | ||
| 71 | + return success(true); | ||
| 72 | + } | ||
| 73 | + | ||
| 74 | + @GetMapping("/send-sms-code-login") | ||
| 75 | + @ApiOperation(value = "向已登录用户发送验证码",notes = "修改手机时验证原手机号使用") | ||
| 76 | + public CommonResult<Boolean> sendSmsCodeLogin() { | ||
| 77 | + smsCodeService.sendSmsCodeLogin(getLoginUserId()); | ||
| 78 | + return success(true); | ||
| 79 | + } | ||
| 80 | + | ||
| 65 | @PostMapping("/reset-password") | 81 | @PostMapping("/reset-password") |
| 66 | @ApiOperation(value = "重置密码", notes = "用户忘记密码时使用") | 82 | @ApiOperation(value = "重置密码", notes = "用户忘记密码时使用") |
| 67 | - public CommonResult<Boolean> resetPassword(@RequestBody @Valid MbrAuthResetPasswordReqVO reqVO) { | ||
| 68 | - return null; | 83 | + public CommonResult<Boolean> resetPassword(@RequestBody @Validated(MbrAuthResetPasswordReqVO.resetPasswordValidView.class) MbrAuthResetPasswordReqVO reqVO) { |
| 84 | + authService.resetPassword(reqVO); | ||
| 85 | + return success(true); | ||
| 86 | + } | ||
| 87 | + | ||
| 88 | + @PostMapping("/update-password") | ||
| 89 | + @ApiOperation(value = "修改用户密码",notes = "用户修改密码时使用") | ||
| 90 | + @PreAuthenticated | ||
| 91 | + public CommonResult<Boolean> updatePassword(@RequestBody @Validated(MbrAuthResetPasswordReqVO.updatePasswordValidView.class) MbrAuthResetPasswordReqVO reqVO) { | ||
| 92 | + authService.updatePassword(getLoginUserId(), reqVO); | ||
| 93 | + return success(true); | ||
| 94 | + } | ||
| 95 | + | ||
| 96 | + @PostMapping("/check-sms-code") | ||
| 97 | + @ApiOperation(value = "校验验证码是否正确") | ||
| 98 | + @PreAuthenticated | ||
| 99 | + public CommonResult<Boolean> checkSmsCode(@RequestBody @Valid SysAuthSmsLoginReqVO reqVO) { | ||
| 100 | + smsCodeService.useSmsCode(reqVO.getMobile(),SysSmsSceneEnum.CHECK_CODE_BY_SMS.getScene(),reqVO.getCode(),getClientIP()); | ||
| 101 | + return success(true); | ||
| 69 | } | 102 | } |
| 70 | 103 | ||
| 71 | // ========== 社交登录相关 ========== | 104 | // ========== 社交登录相关 ========== |
yudao-user-server/src/main/java/cn/iocoder/yudao/userserver/modules/system/controller/auth/vo/MbrAuthResetPasswordReqVO.java
| @@ -8,6 +8,7 @@ import lombok.Data; | @@ -8,6 +8,7 @@ import lombok.Data; | ||
| 8 | import lombok.NoArgsConstructor; | 8 | import lombok.NoArgsConstructor; |
| 9 | import org.hibernate.validator.constraints.Length; | 9 | import org.hibernate.validator.constraints.Length; |
| 10 | 10 | ||
| 11 | +import javax.validation.constraints.NotBlank; | ||
| 11 | import javax.validation.constraints.NotEmpty; | 12 | import javax.validation.constraints.NotEmpty; |
| 12 | import javax.validation.constraints.Pattern; | 13 | import javax.validation.constraints.Pattern; |
| 13 | 14 | ||
| @@ -18,15 +19,31 @@ import javax.validation.constraints.Pattern; | @@ -18,15 +19,31 @@ import javax.validation.constraints.Pattern; | ||
| 18 | @Builder | 19 | @Builder |
| 19 | public class MbrAuthResetPasswordReqVO { | 20 | public class MbrAuthResetPasswordReqVO { |
| 20 | 21 | ||
| 22 | + /** | ||
| 23 | + * 修改密码校验规则 | ||
| 24 | + */ | ||
| 25 | + public interface updatePasswordValidView { | ||
| 26 | + } | ||
| 27 | + | ||
| 28 | + /** | ||
| 29 | + * 忘记密码校验规则 | ||
| 30 | + */ | ||
| 31 | + public interface resetPasswordValidView { | ||
| 32 | + } | ||
| 33 | + | ||
| 34 | + @ApiModelProperty(value = "用户旧密码", required = true, example = "123456") | ||
| 35 | + @NotBlank(message = "旧密码不能为空",groups = updatePasswordValidView.class) | ||
| 36 | + @Length(min = 4, max = 16, message = "密码长度为 4-16 位") | ||
| 37 | + private String oldPassword; | ||
| 38 | + | ||
| 21 | @ApiModelProperty(value = "新密码", required = true, example = "buzhidao") | 39 | @ApiModelProperty(value = "新密码", required = true, example = "buzhidao") |
| 22 | - @NotEmpty(message = "新密码不能为空") | 40 | + @NotEmpty(message = "新密码不能为空",groups = {updatePasswordValidView.class,resetPasswordValidView.class}) |
| 23 | @Length(min = 4, max = 16, message = "密码长度为 4-16 位") | 41 | @Length(min = 4, max = 16, message = "密码长度为 4-16 位") |
| 24 | private String password; | 42 | private String password; |
| 25 | 43 | ||
| 26 | @ApiModelProperty(value = "手机验证码", required = true, example = "1024") | 44 | @ApiModelProperty(value = "手机验证码", required = true, example = "1024") |
| 27 | - @NotEmpty(message = "手机验证码不能为空") | 45 | + @NotEmpty(message = "手机验证码不能为空",groups = resetPasswordValidView.class) |
| 28 | @Length(min = 4, max = 6, message = "手机验证码长度为 4-6 位") | 46 | @Length(min = 4, max = 6, message = "手机验证码长度为 4-6 位") |
| 29 | @Pattern(regexp = "^[0-9]+$", message = "手机验证码必须都是数字") | 47 | @Pattern(regexp = "^[0-9]+$", message = "手机验证码必须都是数字") |
| 30 | private String code; | 48 | private String code; |
| 31 | - | ||
| 32 | } | 49 | } |
yudao-user-server/src/main/java/cn/iocoder/yudao/userserver/modules/system/enums/SysErrorCodeConstants.java
| @@ -23,7 +23,10 @@ public interface SysErrorCodeConstants { | @@ -23,7 +23,10 @@ public interface SysErrorCodeConstants { | ||
| 23 | ErrorCode USER_SMS_CODE_NOT_CORRECT = new ErrorCode(1005001003, "验证码不正确"); | 23 | ErrorCode USER_SMS_CODE_NOT_CORRECT = new ErrorCode(1005001003, "验证码不正确"); |
| 24 | ErrorCode USER_SMS_CODE_EXCEED_SEND_MAXIMUM_QUANTITY_PER_DAY = new ErrorCode(1005001004, "超过每日短信发送数量"); | 24 | ErrorCode USER_SMS_CODE_EXCEED_SEND_MAXIMUM_QUANTITY_PER_DAY = new ErrorCode(1005001004, "超过每日短信发送数量"); |
| 25 | ErrorCode USER_SMS_CODE_SEND_TOO_FAST = new ErrorCode(1005001005, "短信发送过于频率"); | 25 | ErrorCode USER_SMS_CODE_SEND_TOO_FAST = new ErrorCode(1005001005, "短信发送过于频率"); |
| 26 | + ErrorCode USER_SMS_CODE_IS_EXISTS = new ErrorCode(1005001006, "手机号已被使用"); | ||
| 26 | 27 | ||
| 27 | // ========== 用户模块 1005002000 ========== | 28 | // ========== 用户模块 1005002000 ========== |
| 28 | ErrorCode USER_NOT_EXISTS = new ErrorCode(1005002001, "用户不存在"); | 29 | ErrorCode USER_NOT_EXISTS = new ErrorCode(1005002001, "用户不存在"); |
| 30 | + ErrorCode USER_CODE_FAILED = new ErrorCode(1005002002, "验证码不匹配"); | ||
| 31 | + ErrorCode USER_PASSWORD_FAILED = new ErrorCode(1005002003, "密码校验失败"); | ||
| 29 | } | 32 | } |
yudao-user-server/src/main/java/cn/iocoder/yudao/userserver/modules/system/enums/sms/SysSmsSceneEnum.java
| @@ -17,7 +17,9 @@ public enum SysSmsSceneEnum implements IntArrayValuable { | @@ -17,7 +17,9 @@ public enum SysSmsSceneEnum implements IntArrayValuable { | ||
| 17 | 17 | ||
| 18 | LOGIN_BY_SMS(1, "手机号登陆"), | 18 | LOGIN_BY_SMS(1, "手机号登陆"), |
| 19 | CHANGE_MOBILE_BY_SMS(2, "更换手机号"), | 19 | CHANGE_MOBILE_BY_SMS(2, "更换手机号"), |
| 20 | - ; | 20 | + FORGET_MOBILE_BY_SMS(3, "忘记密码"), |
| 21 | + CHECK_CODE_BY_SMS(4, "审核验证码"), | ||
| 22 | + ; | ||
| 21 | 23 | ||
| 22 | public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(SysSmsSceneEnum::getScene).toArray(); | 24 | public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(SysSmsSceneEnum::getScene).toArray(); |
| 23 | 25 |
yudao-user-server/src/main/java/cn/iocoder/yudao/userserver/modules/system/service/auth/SysAuthService.java
| @@ -63,4 +63,23 @@ public interface SysAuthService extends SecurityAuthFrameworkService { | @@ -63,4 +63,23 @@ public interface SysAuthService extends SecurityAuthFrameworkService { | ||
| 63 | */ | 63 | */ |
| 64 | void socialBind(Long userId, @Valid MbrAuthSocialBindReqVO reqVO); | 64 | void socialBind(Long userId, @Valid MbrAuthSocialBindReqVO reqVO); |
| 65 | 65 | ||
| 66 | + /** | ||
| 67 | + * 修改用户密码 | ||
| 68 | + * @param userId 用户id | ||
| 69 | + * @param userReqVO 用户请求实体类 | ||
| 70 | + */ | ||
| 71 | + void updatePassword(Long userId, MbrAuthResetPasswordReqVO userReqVO); | ||
| 72 | + | ||
| 73 | + /** | ||
| 74 | + * 忘记密码 | ||
| 75 | + * @param userReqVO 用户请求实体类 | ||
| 76 | + */ | ||
| 77 | + void resetPassword(MbrAuthResetPasswordReqVO userReqVO); | ||
| 78 | + | ||
| 79 | + /** | ||
| 80 | + * 检测手机与验证码是否匹配 | ||
| 81 | + * @param phone 手机号 | ||
| 82 | + * @param code 验证码 | ||
| 83 | + */ | ||
| 84 | + void checkIfMobileMatchCodeAndDeleteCode(String phone,String code); | ||
| 66 | } | 85 | } |
yudao-user-server/src/main/java/cn/iocoder/yudao/userserver/modules/system/service/auth/impl/SysAuthServiceImpl.java
| @@ -15,15 +15,19 @@ import cn.iocoder.yudao.framework.common.enums.UserTypeEnum; | @@ -15,15 +15,19 @@ import cn.iocoder.yudao.framework.common.enums.UserTypeEnum; | ||
| 15 | import cn.iocoder.yudao.framework.common.util.monitor.TracerUtils; | 15 | import cn.iocoder.yudao.framework.common.util.monitor.TracerUtils; |
| 16 | import cn.iocoder.yudao.framework.common.util.servlet.ServletUtils; | 16 | import cn.iocoder.yudao.framework.common.util.servlet.ServletUtils; |
| 17 | import cn.iocoder.yudao.framework.security.core.LoginUser; | 17 | import cn.iocoder.yudao.framework.security.core.LoginUser; |
| 18 | +import cn.iocoder.yudao.userserver.modules.member.dal.mysql.user.MbrUserMapper; | ||
| 18 | import cn.iocoder.yudao.userserver.modules.member.service.user.MbrUserService; | 19 | import cn.iocoder.yudao.userserver.modules.member.service.user.MbrUserService; |
| 19 | import cn.iocoder.yudao.userserver.modules.system.controller.auth.vo.*; | 20 | import cn.iocoder.yudao.userserver.modules.system.controller.auth.vo.*; |
| 20 | import cn.iocoder.yudao.userserver.modules.system.convert.auth.SysAuthConvert; | 21 | import cn.iocoder.yudao.userserver.modules.system.convert.auth.SysAuthConvert; |
| 21 | import cn.iocoder.yudao.userserver.modules.system.enums.sms.SysSmsSceneEnum; | 22 | import cn.iocoder.yudao.userserver.modules.system.enums.sms.SysSmsSceneEnum; |
| 22 | import cn.iocoder.yudao.userserver.modules.system.service.auth.SysAuthService; | 23 | import cn.iocoder.yudao.userserver.modules.system.service.auth.SysAuthService; |
| 23 | import cn.iocoder.yudao.userserver.modules.system.service.sms.SysSmsCodeService; | 24 | import cn.iocoder.yudao.userserver.modules.system.service.sms.SysSmsCodeService; |
| 25 | +import com.google.common.annotations.VisibleForTesting; | ||
| 24 | import lombok.extern.slf4j.Slf4j; | 26 | import lombok.extern.slf4j.Slf4j; |
| 25 | import me.zhyd.oauth.model.AuthUser; | 27 | import me.zhyd.oauth.model.AuthUser; |
| 28 | +import org.springframework.beans.factory.annotation.Autowired; | ||
| 26 | import org.springframework.context.annotation.Lazy; | 29 | import org.springframework.context.annotation.Lazy; |
| 30 | +import org.springframework.data.redis.core.StringRedisTemplate; | ||
| 27 | import org.springframework.security.authentication.AuthenticationManager; | 31 | import org.springframework.security.authentication.AuthenticationManager; |
| 28 | import org.springframework.security.authentication.BadCredentialsException; | 32 | import org.springframework.security.authentication.BadCredentialsException; |
| 29 | import org.springframework.security.authentication.DisabledException; | 33 | import org.springframework.security.authentication.DisabledException; |
| @@ -32,6 +36,7 @@ import org.springframework.security.core.Authentication; | @@ -32,6 +36,7 @@ import org.springframework.security.core.Authentication; | ||
| 32 | import org.springframework.security.core.AuthenticationException; | 36 | import org.springframework.security.core.AuthenticationException; |
| 33 | import org.springframework.security.core.userdetails.UserDetails; | 37 | import org.springframework.security.core.userdetails.UserDetails; |
| 34 | import org.springframework.security.core.userdetails.UsernameNotFoundException; | 38 | import org.springframework.security.core.userdetails.UsernameNotFoundException; |
| 39 | +import org.springframework.security.crypto.password.PasswordEncoder; | ||
| 35 | import org.springframework.stereotype.Service; | 40 | import org.springframework.stereotype.Service; |
| 36 | import org.springframework.transaction.annotation.Transactional; | 41 | import org.springframework.transaction.annotation.Transactional; |
| 37 | 42 | ||
| @@ -40,6 +45,7 @@ import java.util.List; | @@ -40,6 +45,7 @@ import java.util.List; | ||
| 40 | import java.util.Objects; | 45 | import java.util.Objects; |
| 41 | 46 | ||
| 42 | import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; | 47 | import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; |
| 48 | +import static cn.iocoder.yudao.framework.common.util.servlet.ServletUtils.getClientIP; | ||
| 43 | import static cn.iocoder.yudao.userserver.modules.system.enums.SysErrorCodeConstants.*; | 49 | import static cn.iocoder.yudao.userserver.modules.system.enums.SysErrorCodeConstants.*; |
| 44 | 50 | ||
| 45 | /** | 51 | /** |
| @@ -65,6 +71,13 @@ public class SysAuthServiceImpl implements SysAuthService { | @@ -65,6 +71,13 @@ public class SysAuthServiceImpl implements SysAuthService { | ||
| 65 | private SysUserSessionCoreService userSessionCoreService; | 71 | private SysUserSessionCoreService userSessionCoreService; |
| 66 | @Resource | 72 | @Resource |
| 67 | private SysSocialService socialService; | 73 | private SysSocialService socialService; |
| 74 | + @Resource | ||
| 75 | + private StringRedisTemplate stringRedisTemplate; | ||
| 76 | + @Resource | ||
| 77 | + private PasswordEncoder passwordEncoder; | ||
| 78 | + @Resource | ||
| 79 | + private MbrUserMapper userMapper; | ||
| 80 | + | ||
| 68 | private static final UserTypeEnum userTypeEnum = UserTypeEnum.MEMBER; | 81 | private static final UserTypeEnum userTypeEnum = UserTypeEnum.MEMBER; |
| 69 | 82 | ||
| 70 | @Override | 83 | @Override |
| @@ -200,12 +213,12 @@ public class SysAuthServiceImpl implements SysAuthService { | @@ -200,12 +213,12 @@ public class SysAuthServiceImpl implements SysAuthService { | ||
| 200 | } | 213 | } |
| 201 | reqDTO.setUsername(mobile); | 214 | reqDTO.setUsername(mobile); |
| 202 | reqDTO.setUserAgent(ServletUtils.getUserAgent()); | 215 | reqDTO.setUserAgent(ServletUtils.getUserAgent()); |
| 203 | - reqDTO.setUserIp(ServletUtils.getClientIP()); | 216 | + reqDTO.setUserIp(getClientIP()); |
| 204 | reqDTO.setResult(loginResult.getResult()); | 217 | reqDTO.setResult(loginResult.getResult()); |
| 205 | loginLogCoreService.createLoginLog(reqDTO); | 218 | loginLogCoreService.createLoginLog(reqDTO); |
| 206 | // 更新最后登录时间 | 219 | // 更新最后登录时间 |
| 207 | if (user != null && Objects.equals(SysLoginResultEnum.SUCCESS.getResult(), loginResult.getResult())) { | 220 | if (user != null && Objects.equals(SysLoginResultEnum.SUCCESS.getResult(), loginResult.getResult())) { |
| 208 | - userService.updateUserLogin(user.getId(), ServletUtils.getClientIP()); | 221 | + userService.updateUserLogin(user.getId(), getClientIP()); |
| 209 | } | 222 | } |
| 210 | } | 223 | } |
| 211 | 224 | ||
| @@ -266,6 +279,66 @@ public class SysAuthServiceImpl implements SysAuthService { | @@ -266,6 +279,66 @@ public class SysAuthServiceImpl implements SysAuthService { | ||
| 266 | this.createLogoutLog(loginUser.getId(), loginUser.getUsername()); | 279 | this.createLogoutLog(loginUser.getId(), loginUser.getUsername()); |
| 267 | } | 280 | } |
| 268 | 281 | ||
| 282 | + @Override | ||
| 283 | + public void updatePassword(Long userId, MbrAuthResetPasswordReqVO reqVO) { | ||
| 284 | + // 检验旧密码 | ||
| 285 | + MbrUserDO userDO = checkOldPassword(userId, reqVO.getOldPassword()); | ||
| 286 | + | ||
| 287 | + // 更新用户密码 | ||
| 288 | + userDO.setPassword(passwordEncoder.encode(reqVO.getPassword())); | ||
| 289 | + userMapper.updateById(userDO); | ||
| 290 | + } | ||
| 291 | + | ||
| 292 | + @Override | ||
| 293 | + public void resetPassword(MbrAuthResetPasswordReqVO reqVO) { | ||
| 294 | + // 根据验证码取出手机号,并查询用户 | ||
| 295 | + String mobile = stringRedisTemplate.opsForValue().get(reqVO.getCode()); | ||
| 296 | + MbrUserDO userDO = userMapper.selectByMobile(mobile); | ||
| 297 | + if (userDO == null){ | ||
| 298 | + throw exception(USER_NOT_EXISTS); | ||
| 299 | + } | ||
| 300 | + // TODO @芋艿 这一步没必要检验验证码与手机是否匹配,因为是根据验证码去redis中查找手机号,然后根据手机号查询用户 | ||
| 301 | + // 也就是说 即便黑客以其他方式将验证码发送到自己手机上,最终还是会根据手机号查询用户然后进行重置密码的操作,不存在安全问题 | ||
| 302 | + | ||
| 303 | + // 校验验证码 | ||
| 304 | + smsCodeService.useSmsCode(userDO.getMobile(), SysSmsSceneEnum.FORGET_MOBILE_BY_SMS.getScene(), reqVO.getCode(),getClientIP()); | ||
| 305 | + | ||
| 306 | + // 更新密码 | ||
| 307 | + userDO.setPassword(passwordEncoder.encode(reqVO.getPassword())); | ||
| 308 | + userMapper.updateById(userDO); | ||
| 309 | + } | ||
| 310 | + | ||
| 311 | + @Override | ||
| 312 | + public void checkIfMobileMatchCodeAndDeleteCode(String phone, String code) { | ||
| 313 | + // 检验用户手机与验证码是否匹配 | ||
| 314 | + String mobile = stringRedisTemplate.opsForValue().get(code); | ||
| 315 | + if (!phone.equals(mobile)){ | ||
| 316 | + throw exception(USER_CODE_FAILED); | ||
| 317 | + } | ||
| 318 | + // 销毁redis中此验证码 | ||
| 319 | + stringRedisTemplate.delete(code); | ||
| 320 | + } | ||
| 321 | + | ||
| 322 | + /** | ||
| 323 | + * 校验旧密码 | ||
| 324 | + * | ||
| 325 | + * @param id 用户 id | ||
| 326 | + * @param oldPassword 旧密码 | ||
| 327 | + * @return MbrUserDO 用户实体 | ||
| 328 | + */ | ||
| 329 | + @VisibleForTesting | ||
| 330 | + public MbrUserDO checkOldPassword(Long id, String oldPassword) { | ||
| 331 | + MbrUserDO user = userMapper.selectById(id); | ||
| 332 | + if (user == null) { | ||
| 333 | + throw exception(USER_NOT_EXISTS); | ||
| 334 | + } | ||
| 335 | + // 参数:未加密密码,编码后的密码 | ||
| 336 | + if (!passwordEncoder.matches(oldPassword,user.getPassword())) { | ||
| 337 | + throw exception(USER_PASSWORD_FAILED); | ||
| 338 | + } | ||
| 339 | + return user; | ||
| 340 | + } | ||
| 341 | + | ||
| 269 | private void createLogoutLog(Long userId, String username) { | 342 | private void createLogoutLog(Long userId, String username) { |
| 270 | SysLoginLogCreateReqDTO reqDTO = new SysLoginLogCreateReqDTO(); | 343 | SysLoginLogCreateReqDTO reqDTO = new SysLoginLogCreateReqDTO(); |
| 271 | reqDTO.setLogType(SysLoginLogTypeEnum.LOGOUT_SELF.getType()); | 344 | reqDTO.setLogType(SysLoginLogTypeEnum.LOGOUT_SELF.getType()); |
| @@ -274,7 +347,7 @@ public class SysAuthServiceImpl implements SysAuthService { | @@ -274,7 +347,7 @@ public class SysAuthServiceImpl implements SysAuthService { | ||
| 274 | reqDTO.setUserType(userTypeEnum.getValue()); | 347 | reqDTO.setUserType(userTypeEnum.getValue()); |
| 275 | reqDTO.setUsername(username); | 348 | reqDTO.setUsername(username); |
| 276 | reqDTO.setUserAgent(ServletUtils.getUserAgent()); | 349 | reqDTO.setUserAgent(ServletUtils.getUserAgent()); |
| 277 | - reqDTO.setUserIp(ServletUtils.getClientIP()); | 350 | + reqDTO.setUserIp(getClientIP()); |
| 278 | reqDTO.setResult(SysLoginResultEnum.SUCCESS.getResult()); | 351 | reqDTO.setResult(SysLoginResultEnum.SUCCESS.getResult()); |
| 279 | loginLogCoreService.createLoginLog(reqDTO); | 352 | loginLogCoreService.createLoginLog(reqDTO); |
| 280 | } | 353 | } |
yudao-user-server/src/main/java/cn/iocoder/yudao/userserver/modules/system/service/sms/SysSmsCodeService.java
| @@ -2,6 +2,7 @@ package cn.iocoder.yudao.userserver.modules.system.service.sms; | @@ -2,6 +2,7 @@ package cn.iocoder.yudao.userserver.modules.system.service.sms; | ||
| 2 | 2 | ||
| 3 | import cn.iocoder.yudao.framework.common.exception.ServiceException; | 3 | import cn.iocoder.yudao.framework.common.exception.ServiceException; |
| 4 | import cn.iocoder.yudao.framework.common.validation.Mobile; | 4 | import cn.iocoder.yudao.framework.common.validation.Mobile; |
| 5 | +import cn.iocoder.yudao.userserver.modules.system.controller.auth.vo.SysAuthSendSmsReqVO; | ||
| 5 | import cn.iocoder.yudao.userserver.modules.system.enums.sms.SysSmsSceneEnum; | 6 | import cn.iocoder.yudao.userserver.modules.system.enums.sms.SysSmsSceneEnum; |
| 6 | 7 | ||
| 7 | /** | 8 | /** |
| @@ -21,6 +22,12 @@ public interface SysSmsCodeService { | @@ -21,6 +22,12 @@ public interface SysSmsCodeService { | ||
| 21 | void sendSmsCode(@Mobile String mobile, Integer scene, String createIp); | 22 | void sendSmsCode(@Mobile String mobile, Integer scene, String createIp); |
| 22 | 23 | ||
| 23 | /** | 24 | /** |
| 25 | + * 发送短信验证码,并检测手机号是否已被注册 | ||
| 26 | + * @param reqVO 请求实体 | ||
| 27 | + */ | ||
| 28 | + void sendSmsNewCode(SysAuthSendSmsReqVO reqVO); | ||
| 29 | + | ||
| 30 | + /** | ||
| 24 | * 验证短信验证码,并进行使用 | 31 | * 验证短信验证码,并进行使用 |
| 25 | * 如果正确,则将验证码标记成已使用 | 32 | * 如果正确,则将验证码标记成已使用 |
| 26 | * 如果错误,则抛出 {@link ServiceException} 异常 | 33 | * 如果错误,则抛出 {@link ServiceException} 异常 |
| @@ -32,4 +39,9 @@ public interface SysSmsCodeService { | @@ -32,4 +39,9 @@ public interface SysSmsCodeService { | ||
| 32 | */ | 39 | */ |
| 33 | void useSmsCode(@Mobile String mobile, Integer scene, String code, String usedIp); | 40 | void useSmsCode(@Mobile String mobile, Integer scene, String code, String usedIp); |
| 34 | 41 | ||
| 42 | + /** | ||
| 43 | + * 根据用户id发送验证码 | ||
| 44 | + * @param userId 用户id | ||
| 45 | + */ | ||
| 46 | + void sendSmsCodeLogin(Long userId); | ||
| 35 | } | 47 | } |
yudao-user-server/src/main/java/cn/iocoder/yudao/userserver/modules/system/service/sms/impl/SysSmsCodeServiceImpl.java
| 1 | package cn.iocoder.yudao.userserver.modules.system.service.sms.impl; | 1 | package cn.iocoder.yudao.userserver.modules.system.service.sms.impl; |
| 2 | 2 | ||
| 3 | import cn.hutool.core.map.MapUtil; | 3 | import cn.hutool.core.map.MapUtil; |
| 4 | +import cn.iocoder.yudao.coreservice.modules.member.dal.dataobject.user.MbrUserDO; | ||
| 4 | import cn.iocoder.yudao.coreservice.modules.system.service.sms.SysSmsCoreService; | 5 | import cn.iocoder.yudao.coreservice.modules.system.service.sms.SysSmsCoreService; |
| 6 | +import cn.iocoder.yudao.userserver.modules.member.service.user.MbrUserService; | ||
| 7 | +import cn.iocoder.yudao.userserver.modules.system.controller.auth.vo.SysAuthSendSmsReqVO; | ||
| 5 | import cn.iocoder.yudao.userserver.modules.system.dal.dataobject.sms.SysSmsCodeDO; | 8 | import cn.iocoder.yudao.userserver.modules.system.dal.dataobject.sms.SysSmsCodeDO; |
| 6 | import cn.iocoder.yudao.userserver.modules.system.dal.mysql.sms.SysSmsCodeMapper; | 9 | import cn.iocoder.yudao.userserver.modules.system.dal.mysql.sms.SysSmsCodeMapper; |
| 10 | +import cn.iocoder.yudao.userserver.modules.system.enums.sms.SysSmsSceneEnum; | ||
| 7 | import cn.iocoder.yudao.userserver.modules.system.enums.sms.SysSmsTemplateCodeConstants; | 11 | import cn.iocoder.yudao.userserver.modules.system.enums.sms.SysSmsTemplateCodeConstants; |
| 8 | import cn.iocoder.yudao.userserver.modules.system.framework.sms.SmsCodeProperties; | 12 | import cn.iocoder.yudao.userserver.modules.system.framework.sms.SmsCodeProperties; |
| 9 | import cn.iocoder.yudao.userserver.modules.system.service.sms.SysSmsCodeService; | 13 | import cn.iocoder.yudao.userserver.modules.system.service.sms.SysSmsCodeService; |
| 14 | +import org.springframework.data.redis.core.StringRedisTemplate; | ||
| 10 | import org.springframework.stereotype.Service; | 15 | import org.springframework.stereotype.Service; |
| 11 | import org.springframework.validation.annotation.Validated; | 16 | import org.springframework.validation.annotation.Validated; |
| 12 | 17 | ||
| 13 | import javax.annotation.Resource; | 18 | import javax.annotation.Resource; |
| 14 | import java.util.Date; | 19 | import java.util.Date; |
| 20 | +import java.util.concurrent.TimeUnit; | ||
| 15 | 21 | ||
| 16 | import static cn.hutool.core.util.RandomUtil.randomInt; | 22 | import static cn.hutool.core.util.RandomUtil.randomInt; |
| 17 | import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; | 23 | import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; |
| 24 | +import static cn.iocoder.yudao.framework.common.util.servlet.ServletUtils.getClientIP; | ||
| 18 | import static cn.iocoder.yudao.userserver.modules.system.enums.SysErrorCodeConstants.*; | 25 | import static cn.iocoder.yudao.userserver.modules.system.enums.SysErrorCodeConstants.*; |
| 19 | 26 | ||
| 20 | /** | 27 | /** |
| @@ -26,6 +33,11 @@ import static cn.iocoder.yudao.userserver.modules.system.enums.SysErrorCodeConst | @@ -26,6 +33,11 @@ import static cn.iocoder.yudao.userserver.modules.system.enums.SysErrorCodeConst | ||
| 26 | @Validated | 33 | @Validated |
| 27 | public class SysSmsCodeServiceImpl implements SysSmsCodeService { | 34 | public class SysSmsCodeServiceImpl implements SysSmsCodeService { |
| 28 | 35 | ||
| 36 | + /** | ||
| 37 | + * 验证码 + 手机 在redis中存储的有效时间,单位:分钟 | ||
| 38 | + */ | ||
| 39 | + private static final Long CODE_TIME = 10L; | ||
| 40 | + | ||
| 29 | @Resource | 41 | @Resource |
| 30 | private SmsCodeProperties smsCodeProperties; | 42 | private SmsCodeProperties smsCodeProperties; |
| 31 | 43 | ||
| @@ -33,8 +45,14 @@ public class SysSmsCodeServiceImpl implements SysSmsCodeService { | @@ -33,8 +45,14 @@ public class SysSmsCodeServiceImpl implements SysSmsCodeService { | ||
| 33 | private SysSmsCodeMapper smsCodeMapper; | 45 | private SysSmsCodeMapper smsCodeMapper; |
| 34 | 46 | ||
| 35 | @Resource | 47 | @Resource |
| 48 | + private MbrUserService mbrUserService; | ||
| 49 | + | ||
| 50 | + @Resource | ||
| 36 | private SysSmsCoreService smsCoreService; | 51 | private SysSmsCoreService smsCoreService; |
| 37 | 52 | ||
| 53 | + @Resource | ||
| 54 | + private StringRedisTemplate stringRedisTemplate; | ||
| 55 | + | ||
| 38 | @Override | 56 | @Override |
| 39 | public void sendSmsCode(String mobile, Integer scene, String createIp) { | 57 | public void sendSmsCode(String mobile, Integer scene, String createIp) { |
| 40 | // 创建验证码 | 58 | // 创建验证码 |
| @@ -42,6 +60,21 @@ public class SysSmsCodeServiceImpl implements SysSmsCodeService { | @@ -42,6 +60,21 @@ public class SysSmsCodeServiceImpl implements SysSmsCodeService { | ||
| 42 | // 发送验证码 | 60 | // 发送验证码 |
| 43 | smsCoreService.sendSingleSmsToMember(mobile, null, SysSmsTemplateCodeConstants.USER_SMS_LOGIN, | 61 | smsCoreService.sendSingleSmsToMember(mobile, null, SysSmsTemplateCodeConstants.USER_SMS_LOGIN, |
| 44 | MapUtil.of("code", code)); | 62 | MapUtil.of("code", code)); |
| 63 | + | ||
| 64 | + // 存储手机号与验证码到redis,用于标记 | ||
| 65 | + stringRedisTemplate.opsForValue().set(code,mobile,CODE_TIME, TimeUnit.MINUTES); | ||
| 66 | + } | ||
| 67 | + | ||
| 68 | + @Override | ||
| 69 | + public void sendSmsNewCode(SysAuthSendSmsReqVO reqVO) { | ||
| 70 | + // 检测手机号是否已被使用 | ||
| 71 | + MbrUserDO userByMobile = mbrUserService.getUserByMobile(reqVO.getMobile()); | ||
| 72 | + if (userByMobile != null){ | ||
| 73 | + throw exception(USER_SMS_CODE_IS_EXISTS); | ||
| 74 | + } | ||
| 75 | + | ||
| 76 | + // 发送短信 | ||
| 77 | + this.sendSmsCode(reqVO.getMobile(),reqVO.getScene(),getClientIP()); | ||
| 45 | } | 78 | } |
| 46 | 79 | ||
| 47 | private String createSmsCode(String mobile, Integer scene, String ip) { | 80 | private String createSmsCode(String mobile, Integer scene, String ip) { |
| @@ -91,4 +124,14 @@ public class SysSmsCodeServiceImpl implements SysSmsCodeService { | @@ -91,4 +124,14 @@ public class SysSmsCodeServiceImpl implements SysSmsCodeService { | ||
| 91 | .used(true).usedTime(new Date()).usedIp(usedIp).build()); | 124 | .used(true).usedTime(new Date()).usedIp(usedIp).build()); |
| 92 | } | 125 | } |
| 93 | 126 | ||
| 127 | + @Override | ||
| 128 | + public void sendSmsCodeLogin(Long userId) { | ||
| 129 | + MbrUserDO user = mbrUserService.getUser(userId); | ||
| 130 | + if (user == null){ | ||
| 131 | + throw exception(USER_NOT_EXISTS); | ||
| 132 | + } | ||
| 133 | + // 发送验证码 | ||
| 134 | + this.sendSmsCode(user.getMobile(),SysSmsSceneEnum.CHANGE_MOBILE_BY_SMS.getScene(), getClientIP()); | ||
| 135 | + } | ||
| 136 | + | ||
| 94 | } | 137 | } |
yudao-user-server/src/test/java/cn/iocoder/yudao/userserver/BaseDbAndRedisUnitTest.java
0 → 100644
| 1 | +package cn.iocoder.yudao.userserver; | ||
| 2 | + | ||
| 3 | +import cn.iocoder.yudao.framework.datasource.config.YudaoDataSourceAutoConfiguration; | ||
| 4 | +import cn.iocoder.yudao.framework.mybatis.config.YudaoMybatisAutoConfiguration; | ||
| 5 | +import cn.iocoder.yudao.framework.redis.config.YudaoRedisAutoConfiguration; | ||
| 6 | +import cn.iocoder.yudao.userserver.config.RedisTestConfiguration; | ||
| 7 | +import com.alibaba.druid.spring.boot.autoconfigure.DruidDataSourceAutoConfigure; | ||
| 8 | +import com.baomidou.mybatisplus.autoconfigure.MybatisPlusAutoConfiguration; | ||
| 9 | +import org.redisson.spring.starter.RedissonAutoConfiguration; | ||
| 10 | +import org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration; | ||
| 11 | +import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration; | ||
| 12 | +import org.springframework.boot.autoconfigure.jdbc.DataSourceTransactionManagerAutoConfiguration; | ||
| 13 | +import org.springframework.boot.test.context.SpringBootTest; | ||
| 14 | +import org.springframework.context.annotation.Import; | ||
| 15 | +import org.springframework.test.context.ActiveProfiles; | ||
| 16 | +import org.springframework.test.context.jdbc.Sql; | ||
| 17 | + | ||
| 18 | +/** | ||
| 19 | + * 依赖内存 DB + Redis 的单元测试 | ||
| 20 | + * | ||
| 21 | + * 相比 {@link BaseDbUnitTest} 来说,额外增加了内存 Redis | ||
| 22 | + * | ||
| 23 | + * @author 芋道源码 | ||
| 24 | + */ | ||
| 25 | +@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.NONE, classes = BaseDbAndRedisUnitTest.Application.class) | ||
| 26 | +@ActiveProfiles("unit-test") // 设置使用 application-unit-test 配置文件 | ||
| 27 | +@Sql(scripts = "/sql/clean.sql", executionPhase = Sql.ExecutionPhase.AFTER_TEST_METHOD) // 每个单元测试结束后,清理 DB | ||
| 28 | +public class BaseDbAndRedisUnitTest { | ||
| 29 | + | ||
| 30 | + @Import({ | ||
| 31 | + // DB 配置类 | ||
| 32 | + YudaoDataSourceAutoConfiguration.class, // 自己的 DB 配置类 | ||
| 33 | + DataSourceAutoConfiguration.class, // Spring DB 自动配置类 | ||
| 34 | + DataSourceTransactionManagerAutoConfiguration.class, // Spring 事务自动配置类 | ||
| 35 | + DruidDataSourceAutoConfigure.class, // Druid 自动配置类 | ||
| 36 | + // MyBatis 配置类 | ||
| 37 | + YudaoMybatisAutoConfiguration.class, // 自己的 MyBatis 配置类 | ||
| 38 | + MybatisPlusAutoConfiguration.class, // MyBatis 的自动配置类 | ||
| 39 | + // Redis 配置类 | ||
| 40 | + RedisTestConfiguration.class, // Redis 测试配置类,用于启动 RedisServer | ||
| 41 | + RedisAutoConfiguration.class, // Spring Redis 自动配置类 | ||
| 42 | + YudaoRedisAutoConfiguration.class, // 自己的 Redis 配置类 | ||
| 43 | + RedissonAutoConfiguration.class, // Redisson 自动高配置类 | ||
| 44 | + }) | ||
| 45 | + public static class Application { | ||
| 46 | + } | ||
| 47 | + | ||
| 48 | +} |
yudao-user-server/src/test/java/cn/iocoder/yudao/userserver/config/RedisTestConfiguration.java
0 → 100644
| 1 | +package cn.iocoder.yudao.userserver.config; | ||
| 2 | + | ||
| 3 | +import com.github.fppt.jedismock.RedisServer; | ||
| 4 | +import org.springframework.boot.autoconfigure.data.redis.RedisProperties; | ||
| 5 | +import org.springframework.boot.context.properties.EnableConfigurationProperties; | ||
| 6 | +import org.springframework.context.annotation.Bean; | ||
| 7 | +import org.springframework.context.annotation.Configuration; | ||
| 8 | +import org.springframework.context.annotation.Lazy; | ||
| 9 | + | ||
| 10 | +import java.io.IOException; | ||
| 11 | + | ||
| 12 | +@Configuration(proxyBeanMethods = false) | ||
| 13 | +@Lazy(false) // 禁止延迟加载 | ||
| 14 | +@EnableConfigurationProperties(RedisProperties.class) | ||
| 15 | +public class RedisTestConfiguration { | ||
| 16 | + | ||
| 17 | + /** | ||
| 18 | + * 创建模拟的 Redis Server 服务器 | ||
| 19 | + */ | ||
| 20 | + @Bean | ||
| 21 | + public RedisServer redisServer(RedisProperties properties) throws IOException { | ||
| 22 | + RedisServer redisServer = new RedisServer(properties.getPort()); | ||
| 23 | + // TODO 芋艿:一次执行多个单元测试时,貌似创建多个 spring 容器,导致不进行 stop。这样,就导致端口被占用,无法启动。。。 | ||
| 24 | + try { | ||
| 25 | + redisServer.start(); | ||
| 26 | + } catch (Exception ignore) {} | ||
| 27 | + return redisServer; | ||
| 28 | + } | ||
| 29 | + | ||
| 30 | +} |
yudao-user-server/src/test/java/cn/iocoder/yudao/userserver/modules/member/controller/SysUserProfileControllerTest.java
0 → 100644
| 1 | +package cn.iocoder.yudao.userserver.modules.member.controller; | ||
| 2 | + | ||
| 3 | +import cn.iocoder.yudao.userserver.modules.member.controller.user.SysUserProfileController; | ||
| 4 | +import cn.iocoder.yudao.userserver.modules.member.service.user.MbrUserService; | ||
| 5 | +import cn.iocoder.yudao.userserver.modules.system.service.sms.SysSmsCodeService; | ||
| 6 | +import org.junit.Before; | ||
| 7 | +import org.junit.Test; | ||
| 8 | +import org.mockito.InjectMocks; | ||
| 9 | +import org.mockito.Mock; | ||
| 10 | +import org.mockito.MockitoAnnotations; | ||
| 11 | +import org.springframework.http.MediaType; | ||
| 12 | +import org.springframework.test.web.servlet.MockMvc; | ||
| 13 | +import org.springframework.test.web.servlet.result.MockMvcResultHandlers; | ||
| 14 | +import org.springframework.test.web.servlet.setup.MockMvcBuilders; | ||
| 15 | + | ||
| 16 | + | ||
| 17 | +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; | ||
| 18 | +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; | ||
| 19 | + | ||
| 20 | +/** | ||
| 21 | + * {@link SysUserProfileController} 的单元测试类 | ||
| 22 | + * | ||
| 23 | + * @author 宋天 | ||
| 24 | + */ | ||
| 25 | +public class SysUserProfileControllerTest { | ||
| 26 | + | ||
| 27 | + private MockMvc mockMvc; | ||
| 28 | + | ||
| 29 | + @InjectMocks | ||
| 30 | + private SysUserProfileController sysUserProfileController; | ||
| 31 | + | ||
| 32 | + @Mock | ||
| 33 | + private MbrUserService userService; | ||
| 34 | + | ||
| 35 | + @Mock | ||
| 36 | + private SysSmsCodeService smsCodeService; | ||
| 37 | + | ||
| 38 | + @Before | ||
| 39 | + public void setup() { | ||
| 40 | + // 初始化 | ||
| 41 | + MockitoAnnotations.openMocks(this); | ||
| 42 | + | ||
| 43 | + // 构建mvc环境 | ||
| 44 | + mockMvc = MockMvcBuilders.standaloneSetup(sysUserProfileController).build(); | ||
| 45 | + } | ||
| 46 | + | ||
| 47 | + @Test | ||
| 48 | + public void testUpdateMobile_success() throws Exception { | ||
| 49 | + //模拟接口调用 | ||
| 50 | + this.mockMvc.perform(post("/system/user/profile/update-mobile") | ||
| 51 | + .contentType(MediaType.APPLICATION_JSON_VALUE) | ||
| 52 | + .content("{\"mobile\":\"15819844280\",\"code\":\"123456\"}}")) | ||
| 53 | + .andExpect(status().isOk()) | ||
| 54 | + .andDo(MockMvcResultHandlers.print()); | ||
| 55 | + | ||
| 56 | + } | ||
| 57 | + | ||
| 58 | + | ||
| 59 | +} |
yudao-user-server/src/test/java/cn/iocoder/yudao/userserver/modules/member/service/MbrUserServiceImplTest.java
| @@ -2,28 +2,32 @@ package cn.iocoder.yudao.userserver.modules.member.service; | @@ -2,28 +2,32 @@ package cn.iocoder.yudao.userserver.modules.member.service; | ||
| 2 | 2 | ||
| 3 | import cn.iocoder.yudao.coreservice.modules.infra.service.file.InfFileCoreService; | 3 | import cn.iocoder.yudao.coreservice.modules.infra.service.file.InfFileCoreService; |
| 4 | import cn.iocoder.yudao.coreservice.modules.member.dal.dataobject.user.MbrUserDO; | 4 | import cn.iocoder.yudao.coreservice.modules.member.dal.dataobject.user.MbrUserDO; |
| 5 | -import cn.iocoder.yudao.coreservice.modules.system.dal.dataobject.user.SysUserDO; | ||
| 6 | import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; | 5 | import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; |
| 7 | import cn.iocoder.yudao.framework.common.util.collection.ArrayUtils; | 6 | import cn.iocoder.yudao.framework.common.util.collection.ArrayUtils; |
| 7 | +import cn.iocoder.yudao.framework.redis.config.YudaoRedisAutoConfiguration; | ||
| 8 | +import cn.iocoder.yudao.userserver.BaseDbAndRedisUnitTest; | ||
| 8 | import cn.iocoder.yudao.userserver.BaseDbUnitTest; | 9 | import cn.iocoder.yudao.userserver.BaseDbUnitTest; |
| 9 | import cn.iocoder.yudao.userserver.modules.member.controller.user.vo.MbrUserInfoRespVO; | 10 | import cn.iocoder.yudao.userserver.modules.member.controller.user.vo.MbrUserInfoRespVO; |
| 11 | +import cn.iocoder.yudao.userserver.modules.member.controller.user.vo.MbrUserUpdateMobileReqVO; | ||
| 10 | import cn.iocoder.yudao.userserver.modules.member.dal.mysql.user.MbrUserMapper; | 12 | import cn.iocoder.yudao.userserver.modules.member.dal.mysql.user.MbrUserMapper; |
| 11 | import cn.iocoder.yudao.userserver.modules.member.service.user.impl.MbrUserServiceImpl; | 13 | import cn.iocoder.yudao.userserver.modules.member.service.user.impl.MbrUserServiceImpl; |
| 14 | +import cn.iocoder.yudao.userserver.modules.system.controller.auth.vo.SysAuthSendSmsReqVO; | ||
| 15 | +import cn.iocoder.yudao.userserver.modules.system.enums.sms.SysSmsSceneEnum; | ||
| 16 | +import cn.iocoder.yudao.userserver.modules.system.service.auth.impl.SysAuthServiceImpl; | ||
| 17 | +import cn.iocoder.yudao.userserver.modules.system.service.sms.SysSmsCodeService; | ||
| 18 | +import cn.iocoder.yudao.userserver.modules.system.service.sms.impl.SysSmsCodeServiceImpl; | ||
| 12 | import org.junit.jupiter.api.Test; | 19 | import org.junit.jupiter.api.Test; |
| 13 | import org.springframework.boot.test.mock.mockito.MockBean; | 20 | import org.springframework.boot.test.mock.mockito.MockBean; |
| 14 | import org.springframework.context.annotation.Import; | 21 | import org.springframework.context.annotation.Import; |
| 15 | -import org.springframework.http.MediaType; | ||
| 16 | -import org.springframework.mock.web.MockMultipartFile; | 22 | +import org.springframework.data.redis.core.StringRedisTemplate; |
| 17 | import org.springframework.security.crypto.password.PasswordEncoder; | 23 | import org.springframework.security.crypto.password.PasswordEncoder; |
| 18 | -import org.springframework.util.Assert; | ||
| 19 | 24 | ||
| 20 | import javax.annotation.Resource; | 25 | import javax.annotation.Resource; |
| 21 | import java.io.*; | 26 | import java.io.*; |
| 22 | import java.util.function.Consumer; | 27 | import java.util.function.Consumer; |
| 23 | 28 | ||
| 24 | -import static cn.hutool.core.util.RandomUtil.randomBytes; | 29 | +import static cn.hutool.core.util.RandomUtil.*; |
| 25 | import static org.junit.jupiter.api.Assertions.assertEquals; | 30 | import static org.junit.jupiter.api.Assertions.assertEquals; |
| 26 | -import static cn.hutool.core.util.RandomUtil.randomEle; | ||
| 27 | import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomPojo; | 31 | import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomPojo; |
| 28 | import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomString; | 32 | import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomString; |
| 29 | import static org.mockito.Mockito.*; | 33 | import static org.mockito.Mockito.*; |
| @@ -32,21 +36,30 @@ import static org.mockito.Mockito.*; | @@ -32,21 +36,30 @@ import static org.mockito.Mockito.*; | ||
| 32 | * | 36 | * |
| 33 | * @author 宋天 | 37 | * @author 宋天 |
| 34 | */ | 38 | */ |
| 35 | -@Import(MbrUserServiceImpl.class) | ||
| 36 | -public class MbrUserServiceImplTest extends BaseDbUnitTest { | 39 | +@Import({MbrUserServiceImpl.class, YudaoRedisAutoConfiguration.class}) |
| 40 | +public class MbrUserServiceImplTest extends BaseDbAndRedisUnitTest { | ||
| 37 | 41 | ||
| 38 | @Resource | 42 | @Resource |
| 39 | private MbrUserServiceImpl mbrUserService; | 43 | private MbrUserServiceImpl mbrUserService; |
| 40 | 44 | ||
| 41 | @Resource | 45 | @Resource |
| 46 | + private StringRedisTemplate stringRedisTemplate; | ||
| 47 | + | ||
| 48 | + @Resource | ||
| 42 | private MbrUserMapper userMapper; | 49 | private MbrUserMapper userMapper; |
| 43 | 50 | ||
| 44 | @MockBean | 51 | @MockBean |
| 52 | + private SysAuthServiceImpl authService; | ||
| 53 | + | ||
| 54 | + @MockBean | ||
| 45 | private InfFileCoreService fileCoreService; | 55 | private InfFileCoreService fileCoreService; |
| 46 | 56 | ||
| 47 | @MockBean | 57 | @MockBean |
| 48 | private PasswordEncoder passwordEncoder; | 58 | private PasswordEncoder passwordEncoder; |
| 49 | 59 | ||
| 60 | + @MockBean | ||
| 61 | + private SysSmsCodeService sysSmsCodeService; | ||
| 62 | + | ||
| 50 | @Test | 63 | @Test |
| 51 | public void testUpdateNickName_success(){ | 64 | public void testUpdateNickName_success(){ |
| 52 | // mock 数据 | 65 | // mock 数据 |
| @@ -94,6 +107,37 @@ public class MbrUserServiceImplTest extends BaseDbUnitTest { | @@ -94,6 +107,37 @@ public class MbrUserServiceImplTest extends BaseDbUnitTest { | ||
| 94 | assertEquals(avatar, str); | 107 | assertEquals(avatar, str); |
| 95 | } | 108 | } |
| 96 | 109 | ||
| 110 | + @Test | ||
| 111 | + public void updateMobile_success(){ | ||
| 112 | + // mock数据 | ||
| 113 | + String oldMobile = randomNumbers(11); | ||
| 114 | + MbrUserDO userDO = randomMbrUserDO(); | ||
| 115 | + userDO.setMobile(oldMobile); | ||
| 116 | + userMapper.insert(userDO); | ||
| 117 | + | ||
| 118 | + // 验证旧手机 | ||
| 119 | + sysSmsCodeService.sendSmsCodeLogin(userDO.getId()); | ||
| 120 | + | ||
| 121 | + // 验证旧手机验证码是否正确 | ||
| 122 | + sysSmsCodeService.useSmsCode(oldMobile,SysSmsSceneEnum.CHANGE_MOBILE_BY_SMS.getScene(),"123","1.1.1.1"); | ||
| 123 | + | ||
| 124 | + // 验证新手机 | ||
| 125 | + SysAuthSendSmsReqVO smsReqVO = new SysAuthSendSmsReqVO(); | ||
| 126 | + smsReqVO.setMobile(oldMobile); | ||
| 127 | + smsReqVO.setScene(SysSmsSceneEnum.CHANGE_MOBILE_BY_SMS.getScene()); | ||
| 128 | + sysSmsCodeService.sendSmsNewCode(smsReqVO); | ||
| 129 | + | ||
| 130 | + // 更新手机号 | ||
| 131 | + String newMobile = randomNumbers(11); | ||
| 132 | + String code = randomNumbers(4); | ||
| 133 | + MbrUserUpdateMobileReqVO reqVO = new MbrUserUpdateMobileReqVO(); | ||
| 134 | + reqVO.setMobile(newMobile); | ||
| 135 | + reqVO.setCode(code); | ||
| 136 | + mbrUserService.updateMobile(userDO.getId(),reqVO); | ||
| 137 | + | ||
| 138 | + assertEquals(mbrUserService.getUser(userDO.getId()).getMobile(),newMobile); | ||
| 139 | + } | ||
| 140 | + | ||
| 97 | // ========== 随机对象 ========== | 141 | // ========== 随机对象 ========== |
| 98 | 142 | ||
| 99 | @SafeVarargs | 143 | @SafeVarargs |
yudao-user-server/src/test/java/cn/iocoder/yudao/userserver/modules/system/controller/SysAuthControllerTest.java
0 → 100644
| 1 | +package cn.iocoder.yudao.userserver.modules.system.controller; | ||
| 2 | + | ||
| 3 | +import cn.iocoder.yudao.coreservice.modules.system.service.social.SysSocialService; | ||
| 4 | +import cn.iocoder.yudao.userserver.modules.system.controller.auth.SysAuthController; | ||
| 5 | +import cn.iocoder.yudao.userserver.modules.system.service.auth.SysAuthService; | ||
| 6 | +import cn.iocoder.yudao.userserver.modules.system.service.sms.SysSmsCodeService; | ||
| 7 | +import org.junit.Before; | ||
| 8 | +import org.junit.Test; | ||
| 9 | +import org.mockito.InjectMocks; | ||
| 10 | +import org.mockito.Mock; | ||
| 11 | +import org.mockito.MockitoAnnotations; | ||
| 12 | +import org.springframework.http.MediaType; | ||
| 13 | +import org.springframework.test.web.servlet.MockMvc; | ||
| 14 | +import org.springframework.test.web.servlet.result.MockMvcResultHandlers; | ||
| 15 | +import org.springframework.test.web.servlet.setup.MockMvcBuilders; | ||
| 16 | + | ||
| 17 | +import static org.springframework.http.HttpHeaders.AUTHORIZATION; | ||
| 18 | +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*; | ||
| 19 | +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content; | ||
| 20 | +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; | ||
| 21 | + | ||
| 22 | +/** | ||
| 23 | + * {@link SysAuthController} 的单元测试类 | ||
| 24 | + * | ||
| 25 | + * @author 宋天 | ||
| 26 | + */ | ||
| 27 | +public class SysAuthControllerTest { | ||
| 28 | + | ||
| 29 | + private MockMvc mockMvc; | ||
| 30 | + | ||
| 31 | + @InjectMocks | ||
| 32 | + private SysAuthController sysAuthController; | ||
| 33 | + | ||
| 34 | + @Mock | ||
| 35 | + private SysAuthService authService; | ||
| 36 | + @Mock | ||
| 37 | + private SysSmsCodeService smsCodeService; | ||
| 38 | + @Mock | ||
| 39 | + private SysSocialService socialService; | ||
| 40 | + | ||
| 41 | + | ||
| 42 | + @Before | ||
| 43 | + public void setup() { | ||
| 44 | + // 初始化 | ||
| 45 | + MockitoAnnotations.openMocks(this); | ||
| 46 | + | ||
| 47 | + // 构建mvc环境 | ||
| 48 | + mockMvc = MockMvcBuilders.standaloneSetup(sysAuthController).build(); | ||
| 49 | + } | ||
| 50 | + | ||
| 51 | + @Test | ||
| 52 | + public void testResetPassword_success() throws Exception { | ||
| 53 | + //模拟接口调用 | ||
| 54 | + this.mockMvc.perform(post("/reset-password") | ||
| 55 | + .contentType(MediaType.APPLICATION_JSON) | ||
| 56 | + .content("{\"password\":\"1123\",\"code\":\"123456\"}}")) | ||
| 57 | + .andExpect(status().isOk()) | ||
| 58 | + .andDo(MockMvcResultHandlers.print()); | ||
| 59 | + | ||
| 60 | + } | ||
| 61 | + | ||
| 62 | + @Test | ||
| 63 | + public void testUpdatePassword_success() throws Exception { | ||
| 64 | + //模拟接口调用 | ||
| 65 | + this.mockMvc.perform(post("/update-password") | ||
| 66 | + .contentType(MediaType.APPLICATION_JSON) | ||
| 67 | + .content("{\"password\":\"1123\",\"code\":\"123456\",\"oldPassword\":\"1123\"}}")) | ||
| 68 | + .andExpect(status().isOk()) | ||
| 69 | + .andDo(MockMvcResultHandlers.print()); | ||
| 70 | + | ||
| 71 | + } | ||
| 72 | + | ||
| 73 | + | ||
| 74 | + | ||
| 75 | +} |
yudao-user-server/src/test/java/cn/iocoder/yudao/userserver/modules/system/service/SysAuthServiceTest.java
0 → 100644
| 1 | +package cn.iocoder.yudao.userserver.modules.system.service; | ||
| 2 | + | ||
| 3 | +import cn.hutool.core.util.ArrayUtil; | ||
| 4 | +import cn.iocoder.yudao.coreservice.modules.member.dal.dataobject.user.MbrUserDO; | ||
| 5 | +import cn.iocoder.yudao.coreservice.modules.system.dal.dataobject.user.SysUserDO; | ||
| 6 | +import cn.iocoder.yudao.coreservice.modules.system.service.auth.SysUserSessionCoreService; | ||
| 7 | +import cn.iocoder.yudao.coreservice.modules.system.service.logger.SysLoginLogCoreService; | ||
| 8 | +import cn.iocoder.yudao.coreservice.modules.system.service.social.SysSocialService; | ||
| 9 | +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; | ||
| 10 | +import cn.iocoder.yudao.framework.common.util.collection.ArrayUtils; | ||
| 11 | +import cn.iocoder.yudao.framework.redis.config.YudaoRedisAutoConfiguration; | ||
| 12 | +import cn.iocoder.yudao.userserver.BaseDbAndRedisUnitTest; | ||
| 13 | +import cn.iocoder.yudao.userserver.BaseDbUnitTest; | ||
| 14 | +import cn.iocoder.yudao.userserver.config.RedisTestConfiguration; | ||
| 15 | +import cn.iocoder.yudao.userserver.modules.member.dal.mysql.user.MbrUserMapper; | ||
| 16 | +import cn.iocoder.yudao.userserver.modules.member.service.user.MbrUserService; | ||
| 17 | +import cn.iocoder.yudao.userserver.modules.member.service.user.impl.MbrUserServiceImpl; | ||
| 18 | +import cn.iocoder.yudao.userserver.modules.system.controller.auth.vo.MbrAuthResetPasswordReqVO; | ||
| 19 | +import cn.iocoder.yudao.userserver.modules.system.service.auth.SysAuthService; | ||
| 20 | +import cn.iocoder.yudao.userserver.modules.system.service.auth.impl.SysAuthServiceImpl; | ||
| 21 | +import cn.iocoder.yudao.userserver.modules.system.service.sms.SysSmsCodeService; | ||
| 22 | +import org.junit.jupiter.api.Test; | ||
| 23 | +import org.springframework.boot.test.mock.mockito.MockBean; | ||
| 24 | +import org.springframework.context.annotation.Import; | ||
| 25 | +import org.springframework.data.redis.core.StringRedisTemplate; | ||
| 26 | +import org.springframework.security.authentication.AuthenticationManager; | ||
| 27 | +import org.springframework.security.crypto.password.PasswordEncoder; | ||
| 28 | + | ||
| 29 | +import javax.annotation.Resource; | ||
| 30 | + | ||
| 31 | +import java.util.concurrent.TimeUnit; | ||
| 32 | +import java.util.function.Consumer; | ||
| 33 | + | ||
| 34 | +import static cn.hutool.core.util.RandomUtil.randomEle; | ||
| 35 | +import static cn.hutool.core.util.RandomUtil.randomNumbers; | ||
| 36 | +import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.*; | ||
| 37 | +import static org.junit.jupiter.api.Assertions.assertEquals; | ||
| 38 | +import static org.mockito.Mockito.*; | ||
| 39 | + | ||
| 40 | + | ||
| 41 | +/** | ||
| 42 | + * {@link SysAuthService} 的单元测试类 | ||
| 43 | + * | ||
| 44 | + * @author 宋天 | ||
| 45 | + */ | ||
| 46 | +@Import({SysAuthServiceImpl.class, YudaoRedisAutoConfiguration.class}) | ||
| 47 | +public class SysAuthServiceTest extends BaseDbAndRedisUnitTest { | ||
| 48 | + | ||
| 49 | + @MockBean | ||
| 50 | + private AuthenticationManager authenticationManager; | ||
| 51 | + @MockBean | ||
| 52 | + private MbrUserService userService; | ||
| 53 | + @MockBean | ||
| 54 | + private SysSmsCodeService smsCodeService; | ||
| 55 | + @MockBean | ||
| 56 | + private SysLoginLogCoreService loginLogCoreService; | ||
| 57 | + @MockBean | ||
| 58 | + private SysUserSessionCoreService userSessionCoreService; | ||
| 59 | + @MockBean | ||
| 60 | + private SysSocialService socialService; | ||
| 61 | + @Resource | ||
| 62 | + private StringRedisTemplate stringRedisTemplate; | ||
| 63 | + @MockBean | ||
| 64 | + private PasswordEncoder passwordEncoder; | ||
| 65 | + @Resource | ||
| 66 | + private MbrUserMapper mbrUserMapper; | ||
| 67 | + @Resource | ||
| 68 | + private SysAuthServiceImpl authService; | ||
| 69 | + | ||
| 70 | + | ||
| 71 | + @Test | ||
| 72 | + public void testUpdatePassword_success(){ | ||
| 73 | + // 准备参数 | ||
| 74 | + MbrUserDO userDO = randomMbrUserDO(); | ||
| 75 | + mbrUserMapper.insert(userDO); | ||
| 76 | + | ||
| 77 | + // 新密码 | ||
| 78 | + String newPassword = randomString(); | ||
| 79 | + | ||
| 80 | + // 请求实体 | ||
| 81 | + MbrAuthResetPasswordReqVO reqVO = new MbrAuthResetPasswordReqVO(); | ||
| 82 | + reqVO.setOldPassword(userDO.getPassword()); | ||
| 83 | + reqVO.setPassword(newPassword); | ||
| 84 | + | ||
| 85 | + // 测试桩 | ||
| 86 | + // 这两个相等是为了返回ture这个结果 | ||
| 87 | + when(passwordEncoder.matches(reqVO.getOldPassword(),reqVO.getOldPassword())).thenReturn(true); | ||
| 88 | + when(passwordEncoder.encode(newPassword)).thenReturn(newPassword); | ||
| 89 | + | ||
| 90 | + // 更新用户密码 | ||
| 91 | + authService.updatePassword(userDO.getId(),reqVO); | ||
| 92 | + assertEquals(mbrUserMapper.selectById(userDO.getId()).getPassword(),newPassword); | ||
| 93 | + } | ||
| 94 | + | ||
| 95 | + @Test | ||
| 96 | + public void testResetPassword_success(){ | ||
| 97 | + // 准备参数 | ||
| 98 | + MbrUserDO userDO = randomMbrUserDO(); | ||
| 99 | + mbrUserMapper.insert(userDO); | ||
| 100 | + | ||
| 101 | + // 随机密码 | ||
| 102 | + String password = randomNumbers(11); | ||
| 103 | + // 随机验证码 | ||
| 104 | + String code = randomNumbers(4); | ||
| 105 | + | ||
| 106 | + MbrAuthResetPasswordReqVO reqVO = new MbrAuthResetPasswordReqVO(); | ||
| 107 | + reqVO.setPassword(password); | ||
| 108 | + reqVO.setCode(code); | ||
| 109 | + | ||
| 110 | + // 放入code+手机号 | ||
| 111 | + stringRedisTemplate.opsForValue().set(code,userDO.getMobile(),10, TimeUnit.MINUTES); | ||
| 112 | + | ||
| 113 | + // mock | ||
| 114 | + when(passwordEncoder.encode(password)).thenReturn(password); | ||
| 115 | + | ||
| 116 | + // 更新用户密码 | ||
| 117 | + authService.resetPassword(reqVO); | ||
| 118 | + assertEquals(mbrUserMapper.selectById(userDO.getId()).getPassword(),password); | ||
| 119 | + } | ||
| 120 | + | ||
| 121 | + | ||
| 122 | + // ========== 随机对象 ========== | ||
| 123 | + | ||
| 124 | + @SafeVarargs | ||
| 125 | + private static MbrUserDO randomMbrUserDO(Consumer<MbrUserDO>... consumers) { | ||
| 126 | + Consumer<MbrUserDO> consumer = (o) -> { | ||
| 127 | + o.setStatus(randomEle(CommonStatusEnum.values()).getStatus()); // 保证 status 的范围 | ||
| 128 | + o.setPassword(randomString()); | ||
| 129 | + }; | ||
| 130 | + return randomPojo(MbrUserDO.class, ArrayUtils.append(consumer, consumers)); | ||
| 131 | + } | ||
| 132 | + | ||
| 133 | + | ||
| 134 | +} |