!60 用户中心修改密码,修改手机功能重做,发送短信 拓展设置对应模板编号

Merge pull request !60 from 宋天/feature/user-register
pull/2/head
芋道源码 2022-01-26 10:51:54 +00:00 committed by Gitee
commit 678e2def97
No known key found for this signature in database
GPG Key ID: 173E9B9CA92EEF8F
20 changed files with 235 additions and 292 deletions

View File

@ -55,6 +55,19 @@ spring:
username: root username: root
password: 123456 password: 123456
activiti:
#1.false:默认值activiti启动时对比数据库表中保存的版本如果不匹配。将抛出异常
#2.true:启动时会对数据库中所有表进行更新操作,如果表存在,不做处理,反之,自动创建表
#3.create_drop:启动时自动创建表,关闭时自动删除表
#4.drop_create:启动时,删除旧表,再创建新表
database-schema-update: true
#activiti7默认不生成历史信息表需手动设置开启
db-history-used: true
check-process-definitions: true
#full保存历史数据的最高级别可保存全部流程相关细节包括流程流转各节点参数
history-level: full
# Redis 配置。Redisson 默认的配置足够使用,一般不需要进行调优 # Redis 配置。Redisson 默认的配置足够使用,一般不需要进行调优
redis: redis:
host: 127.0.0.1 # 地址 host: 127.0.0.1 # 地址

View File

@ -90,15 +90,6 @@
<artifactId>yudao-spring-boot-starter-test</artifactId> <artifactId>yudao-spring-boot-starter-test</artifactId>
<scope>test</scope> <scope>test</scope>
</dependency> </dependency>
<!-- TODO @宋天junit 已经在 yudao-spring-boot-starter-test 啦,不用在引入哈 -->
<!--单元测试相关-->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<scope>test</scope>
</dependency>
<!-- 工具类相关 --> <!-- 工具类相关 -->
</dependencies> </dependencies>

View File

@ -35,9 +35,6 @@ public class SysUserProfileController {
@Resource @Resource
private MbrUserService userService; private MbrUserService userService;
@Resource
private SysSmsCodeService smsCodeService;
@PutMapping("/update-nickname") @PutMapping("/update-nickname")
@ApiOperation("修改用户昵称") @ApiOperation("修改用户昵称")
@PreAuthenticated @PreAuthenticated
@ -68,10 +65,6 @@ public class SysUserProfileController {
@ApiOperation(value = "修改用户手机") @ApiOperation(value = "修改用户手机")
@PreAuthenticated @PreAuthenticated
public CommonResult<Boolean> updateMobile(@RequestBody @Valid MbrUserUpdateMobileReqVO reqVO) { public CommonResult<Boolean> updateMobile(@RequestBody @Valid MbrUserUpdateMobileReqVO reqVO) {
// 校验验证码
// TODO @宋天:统一到 userService.updateMobile 方法里
smsCodeService.useSmsCode(reqVO.getMobile(),SysSmsSceneEnum.CHANGE_MOBILE_BY_SMS.getScene(), reqVO.getCode(),getClientIP());
userService.updateMobile(getLoginUserId(), reqVO); userService.updateMobile(getLoginUserId(), reqVO);
return success(true); return success(true);
} }

View File

@ -1,5 +1,6 @@
package cn.iocoder.yudao.userserver.modules.member.controller.user.vo; package cn.iocoder.yudao.userserver.modules.member.controller.user.vo;
import cn.iocoder.yudao.framework.common.validation.Mobile;
import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty; import io.swagger.annotations.ApiModelProperty;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;
@ -27,9 +28,21 @@ public class MbrUserUpdateMobileReqVO {
@ApiModelProperty(value = "手机号",required = true,example = "15823654487") @ApiModelProperty(value = "手机号",required = true,example = "15823654487")
@NotBlank(message = "手机号不能为空") @NotBlank(message = "手机号不能为空")
// TODO @宋天:手机校验,直接使用 @Mobile 哈
@Length(min = 8, max = 11, message = "手机号码长度为 8-11 位") @Length(min = 8, max = 11, message = "手机号码长度为 8-11 位")
@Pattern(regexp = "^1[3-9]\\d{9}$", message = "手机号格式错误") @Mobile
private String mobile; private String mobile;
@ApiModelProperty(value = "原手机验证码", required = true, example = "1024")
@NotEmpty(message = "原手机验证码不能为空")
@Length(min = 4, max = 6, message = "手机验证码长度为 4-6 位")
@Pattern(regexp = "^[0-9]+$", message = "手机验证码必须都是数字")
private String oldCode;
@ApiModelProperty(value = "原手机号",required = true,example = "15823654487")
@NotBlank(message = "手机号不能为空")
@Length(min = 8, max = 11, message = "手机号码长度为 8-11 位")
@Mobile
private String oldMobile;
} }

View File

@ -4,17 +4,20 @@ import cn.hutool.core.io.IoUtil;
import cn.hutool.core.util.IdUtil; import cn.hutool.core.util.IdUtil;
import cn.iocoder.yudao.coreservice.modules.infra.service.file.InfFileCoreService; import cn.iocoder.yudao.coreservice.modules.infra.service.file.InfFileCoreService;
import cn.iocoder.yudao.coreservice.modules.member.dal.dataobject.user.MbrUserDO; import cn.iocoder.yudao.coreservice.modules.member.dal.dataobject.user.MbrUserDO;
import cn.iocoder.yudao.userserver.modules.member.controller.user.vo.MbrUserInfoRespVO;
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
import cn.iocoder.yudao.userserver.modules.member.controller.user.vo.MbrUserInfoRespVO;
import cn.iocoder.yudao.userserver.modules.member.controller.user.vo.MbrUserUpdateMobileReqVO; import cn.iocoder.yudao.userserver.modules.member.controller.user.vo.MbrUserUpdateMobileReqVO;
import cn.iocoder.yudao.userserver.modules.member.convert.user.UserProfileConvert; import cn.iocoder.yudao.userserver.modules.member.convert.user.UserProfileConvert;
import cn.iocoder.yudao.userserver.modules.member.dal.mysql.user.MbrUserMapper; import cn.iocoder.yudao.userserver.modules.member.dal.mysql.user.MbrUserMapper;
import cn.iocoder.yudao.userserver.modules.member.service.user.MbrUserService; import cn.iocoder.yudao.userserver.modules.member.service.user.MbrUserService;
import cn.iocoder.yudao.userserver.modules.system.service.auth.SysAuthService; import cn.iocoder.yudao.userserver.modules.system.dal.dataobject.sms.SysSmsCodeDO;
import cn.iocoder.yudao.userserver.modules.system.enums.sms.SysSmsSceneEnum;
import cn.iocoder.yudao.userserver.modules.system.service.sms.SysSmsCodeService;
import com.google.common.annotations.VisibleForTesting; import com.google.common.annotations.VisibleForTesting;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import javax.annotation.Resource; import javax.annotation.Resource;
import javax.validation.Valid; import javax.validation.Valid;
@ -22,7 +25,9 @@ import java.io.InputStream;
import java.util.Date; import java.util.Date;
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; 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.userserver.modules.member.enums.MbrErrorCodeConstants.USER_NOT_EXISTS; import static cn.iocoder.yudao.userserver.modules.member.enums.MbrErrorCodeConstants.USER_NOT_EXISTS;
import static cn.iocoder.yudao.userserver.modules.system.enums.SysErrorCodeConstants.USER_SMS_CODE_IS_UNUSED;
/** /**
* User Service * User Service
@ -44,7 +49,8 @@ public class MbrUserServiceImpl implements MbrUserService {
private PasswordEncoder passwordEncoder; private PasswordEncoder passwordEncoder;
@Resource @Resource
private SysAuthService sysAuthService; private SysSmsCodeService smsCodeService;
@Override @Override
public MbrUserDO getUserByMobile(String mobile) { public MbrUserDO getUserByMobile(String mobile) {
@ -120,15 +126,23 @@ public class MbrUserServiceImpl implements MbrUserService {
} }
@Override @Override
@Transactional(rollbackFor = Exception.class)
public void updateMobile(Long userId, MbrUserUpdateMobileReqVO reqVO) { public void updateMobile(Long userId, MbrUserUpdateMobileReqVO reqVO) {
// 检测用户是否存在 // 检测用户是否存在
MbrUserDO userDO = checkUserExists(userId); checkUserExists(userId);
// 检测手机与验证码是否匹配
// TODO @宋天:修改手机的时候。应该要校验,老手机 + 老手机 code新手机 + 新手机 code // 校验旧手机和旧验证码
sysAuthService.checkIfMobileMatchCodeAndDeleteCode(userDO.getMobile(),reqVO.getCode()); SysSmsCodeDO sysSmsCodeDO = smsCodeService.checkCodeIsExpired(reqVO.getOldMobile(), reqVO.getOldCode(), SysSmsSceneEnum.CHANGE_MOBILE_BY_SMS.getScene());
// 判断旧code是否未被使用如果是抛出异常
if (Boolean.FALSE.equals(sysSmsCodeDO.getUsed())){
throw exception(USER_SMS_CODE_IS_UNUSED);
}
// 使用新验证码
smsCodeService.useSmsCode(reqVO.getMobile(), SysSmsSceneEnum.CHANGE_MOBILE_BY_SMS.getScene(), reqVO.getCode(),getClientIP());
// 更新用户手机 // 更新用户手机
// TODO @宋天:更新的时候,单独创建对象。直接全量更新,会可能导致属性覆盖。可以看看打印出来的 SQL 哈 MbrUserDO userDO = MbrUserDO.builder().id(userId).mobile(reqVO.getMobile()).build();
userDO.setMobile(reqVO.getMobile());
userMapper.updateById(userDO); userMapper.updateById(userDO);
} }

View File

@ -5,10 +5,8 @@ import cn.iocoder.yudao.framework.common.enums.UserTypeEnum;
import cn.iocoder.yudao.framework.common.pojo.CommonResult; import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.framework.security.core.annotations.PreAuthenticated; import cn.iocoder.yudao.framework.security.core.annotations.PreAuthenticated;
import cn.iocoder.yudao.userserver.modules.system.controller.auth.vo.*; import cn.iocoder.yudao.userserver.modules.system.controller.auth.vo.*;
import cn.iocoder.yudao.userserver.modules.system.enums.sms.SysSmsSceneEnum;
import cn.iocoder.yudao.userserver.modules.system.service.auth.SysAuthService; import cn.iocoder.yudao.userserver.modules.system.service.auth.SysAuthService;
import cn.iocoder.yudao.userserver.modules.system.service.sms.SysSmsCodeService; import cn.iocoder.yudao.userserver.modules.system.service.sms.SysSmsCodeService;
import com.alibaba.fastjson.JSON;
import io.swagger.annotations.Api; import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam; import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams; import io.swagger.annotations.ApiImplicitParams;
@ -18,7 +16,6 @@ import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*; import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource; import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.validation.Valid; import javax.validation.Valid;
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
@ -57,19 +54,12 @@ public class SysAuthController {
} }
@PostMapping("/send-sms-code") @PostMapping("/send-sms-code")
@ApiOperation(value = "发送手机验证码",notes = "不检测该手机号是否已被注册") @ApiOperation(value = "发送手机验证码")
public CommonResult<Boolean> sendSmsCode(@RequestBody @Valid SysAuthSendSmsReqVO reqVO) { public CommonResult<Boolean> sendSmsCode(@RequestBody @Valid SysAuthSendSmsReqVO reqVO) {
smsCodeService.sendSmsCode(reqVO.getMobile(), reqVO.getScene(), getClientIP()); smsCodeService.sendSmsCode(reqVO.getMobile(), reqVO.getScene(), getClientIP());
return success(true); return success(true);
} }
@PostMapping("/send-sms-new-code")
@ApiOperation(value = "发送手机验证码",notes = "检测该手机号是否已被注册,用于修改手机时使用")
public CommonResult<Boolean> sendSmsNewCode(@RequestBody @Valid SysAuthSendSmsReqVO reqVO) {
smsCodeService.sendSmsNewCode(reqVO);
return success(true);
}
@GetMapping("/send-sms-code-login") @GetMapping("/send-sms-code-login")
@ApiOperation(value = "向已登录用户发送验证码",notes = "修改手机时验证原手机号使用") @ApiOperation(value = "向已登录用户发送验证码",notes = "修改手机时验证原手机号使用")
public CommonResult<Boolean> sendSmsCodeLogin() { public CommonResult<Boolean> sendSmsCodeLogin() {
@ -93,14 +83,6 @@ public class SysAuthController {
return success(true); return success(true);
} }
@PostMapping("/check-sms-code")
@ApiOperation(value = "校验验证码是否正确")
@PreAuthenticated
public CommonResult<Boolean> checkSmsCode(@RequestBody @Valid SysAuthSmsLoginReqVO reqVO) {
// TODO @宋天check 的时候,不应该使用 useSmsCode 哈这样验证码就直接被使用了。另外check 开头的方法,更多是校验的逻辑,不会有 update 数据的动作。这点,在方法命名上,也是要注意的
smsCodeService.useSmsCode(reqVO.getMobile(),SysSmsSceneEnum.CHECK_CODE_BY_SMS.getScene(),reqVO.getCode(),getClientIP());
return success(true);
}
// ========== 社交登录相关 ========== // ========== 社交登录相关 ==========

View File

@ -1,5 +1,6 @@
package cn.iocoder.yudao.userserver.modules.system.controller.auth.vo; package cn.iocoder.yudao.userserver.modules.system.controller.auth.vo;
import cn.iocoder.yudao.framework.common.validation.Mobile;
import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty; import io.swagger.annotations.ApiModelProperty;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;
@ -8,6 +9,7 @@ import lombok.Data;
import lombok.NoArgsConstructor; import lombok.NoArgsConstructor;
import org.hibernate.validator.constraints.Length; import org.hibernate.validator.constraints.Length;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotEmpty; import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.Pattern; import javax.validation.constraints.Pattern;
@ -29,4 +31,8 @@ public class MbrAuthResetPasswordReqVO {
@Pattern(regexp = "^[0-9]+$", message = "手机验证码必须都是数字") @Pattern(regexp = "^[0-9]+$", message = "手机验证码必须都是数字")
private String code; private String code;
@ApiModelProperty(value = "手机号",required = true,example = "15878962356")
@NotBlank(message = "手机号不能为空")
@Mobile
private String mobile;
} }

View File

@ -0,0 +1,40 @@
package cn.iocoder.yudao.userserver.modules.system.controller.auth.vo;
import cn.iocoder.yudao.framework.common.validation.InEnum;
import cn.iocoder.yudao.framework.common.validation.Mobile;
import cn.iocoder.yudao.userserver.modules.system.enums.sms.SysSmsSceneEnum;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.hibernate.validator.constraints.Length;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Pattern;
@ApiModel("校验验证码 Request VO")
@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class SysAuthCheckCodeReqVO {
@ApiModelProperty(value = "手机号", example = "15601691234")
@NotBlank(message = "手机号不能为空")
@Mobile
private String mobile;
@ApiModelProperty(value = "手机验证码", required = true, example = "1024")
@NotBlank(message = "手机验证码不能为空")
@Length(min = 4, max = 6, message = "手机验证码长度为 4-6 位")
@Pattern(regexp = "^[0-9]+$", message = "手机验证码必须都是数字")
private String code;
@ApiModelProperty(value = "发送场景", example = "1", notes = "对应 MbrSmsSceneEnum 枚举")
@NotNull(message = "发送场景不能为空")
@InEnum(SysSmsSceneEnum.class)
private Integer scene;
}

View File

@ -5,6 +5,7 @@ import cn.iocoder.yudao.framework.mybatis.core.query.QueryWrapperX;
import cn.iocoder.yudao.userserver.modules.system.dal.dataobject.sms.SysSmsCodeDO; import cn.iocoder.yudao.userserver.modules.system.dal.dataobject.sms.SysSmsCodeDO;
import org.apache.ibatis.annotations.Mapper; import org.apache.ibatis.annotations.Mapper;
@Mapper @Mapper
public interface SysSmsCodeMapper extends BaseMapperX<SysSmsCodeDO> { public interface SysSmsCodeMapper extends BaseMapperX<SysSmsCodeDO> {
@ -13,14 +14,15 @@ public interface SysSmsCodeMapper extends BaseMapperX<SysSmsCodeDO> {
* *
* @param mobile * @param mobile
* @param scene * @param scene
* @param code
* @return * @return
*/ */
default SysSmsCodeDO selectLastByMobile(String mobile, Integer scene) { default SysSmsCodeDO selectLastByMobile(String mobile,String code,Integer scene) {
return selectOne(new QueryWrapperX<SysSmsCodeDO>() return selectOne(new QueryWrapperX<SysSmsCodeDO>()
.eq("mobile", mobile) .eq("mobile", mobile)
.eqIfPresent("scene", scene) .eqIfPresent("scene", scene)
.eqIfPresent("code", code)
.orderByDesc("id") .orderByDesc("id")
.last("LIMIT 1")); .last("LIMIT 1"));
} }
} }

View File

@ -24,9 +24,9 @@ public interface SysErrorCodeConstants {
ErrorCode USER_SMS_CODE_EXCEED_SEND_MAXIMUM_QUANTITY_PER_DAY = new ErrorCode(1005001004, "超过每日短信发送数量"); ErrorCode USER_SMS_CODE_EXCEED_SEND_MAXIMUM_QUANTITY_PER_DAY = new ErrorCode(1005001004, "超过每日短信发送数量");
ErrorCode USER_SMS_CODE_SEND_TOO_FAST = new ErrorCode(1005001005, "短信发送过于频率"); ErrorCode USER_SMS_CODE_SEND_TOO_FAST = new ErrorCode(1005001005, "短信发送过于频率");
ErrorCode USER_SMS_CODE_IS_EXISTS = new ErrorCode(1005001006, "手机号已被使用"); ErrorCode USER_SMS_CODE_IS_EXISTS = new ErrorCode(1005001006, "手机号已被使用");
ErrorCode USER_SMS_CODE_IS_UNUSED = new ErrorCode(1005001006, "验证码未被使用");
// ========== 用户模块 1005002000 ========== // ========== 用户模块 1005002000 ==========
ErrorCode USER_NOT_EXISTS = new ErrorCode(1005002001, "用户不存在"); ErrorCode USER_NOT_EXISTS = new ErrorCode(1005002001, "用户不存在");
ErrorCode USER_CODE_FAILED = new ErrorCode(1005002002, "验证码不匹配");
ErrorCode USER_PASSWORD_FAILED = new ErrorCode(1005002003, "密码校验失败"); ErrorCode USER_PASSWORD_FAILED = new ErrorCode(1005002003, "密码校验失败");
} }

View File

@ -15,15 +15,26 @@ import java.util.Arrays;
@AllArgsConstructor @AllArgsConstructor
public enum SysSmsSceneEnum implements IntArrayValuable { public enum SysSmsSceneEnum implements IntArrayValuable {
LOGIN_BY_SMS(1, "手机号登陆"), LOGIN_BY_SMS(1,SysSmsTemplateCodeConstants.USER_SMS_LOGIN, "手机号登陆"),
CHANGE_MOBILE_BY_SMS(2, "更换手机号"), CHANGE_MOBILE_BY_SMS(2,SysSmsTemplateCodeConstants.USER_SMS_UPDATE_MOBILE, "更换手机号"),
FORGET_MOBILE_BY_SMS(3, "忘记密码"), FORGET_MOBILE_BY_SMS(3,SysSmsTemplateCodeConstants.USER_SMS_RESET_PASSWORD, "忘记密码"),
CHECK_CODE_BY_SMS(4, "审核验证码"),
; ;
public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(SysSmsSceneEnum::getScene).toArray(); public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(SysSmsSceneEnum::getScene).toArray();
/**
*
*/
private final Integer scene; private final Integer scene;
/**
*
*/
private final String code;
/**
*
*/
private final String name; private final String name;
@Override @Override
@ -31,4 +42,13 @@ public enum SysSmsSceneEnum implements IntArrayValuable {
return ARRAYS; return ARRAYS;
} }
public static String getCodeByScene(Integer scene){
for (SysSmsSceneEnum value : values()) {
if (value.getScene().equals(scene)){
return value.getCode();
}
}
return null;
}
} }

View File

@ -12,4 +12,14 @@ public interface SysSmsTemplateCodeConstants {
*/ */
String USER_SMS_LOGIN = "user-sms-login"; String USER_SMS_LOGIN = "user-sms-login";
/**
*
*/
String USER_SMS_RESET_PASSWORD = "user-sms-reset-password";
/**
*
*/
String USER_SMS_UPDATE_MOBILE = "user-sms-update-mobile";
} }

View File

@ -68,18 +68,11 @@ public interface SysAuthService extends SecurityAuthFrameworkService {
* @param userId id * @param userId id
* @param userReqVO * @param userReqVO
*/ */
void updatePassword(Long userId, @Valid MbrAuthUpdatePasswordReqVO userReqVO); void updatePassword(Long userId,MbrAuthUpdatePasswordReqVO userReqVO);
/** /**
* *
* @param userReqVO * @param userReqVO
*/ */
void resetPassword(MbrAuthResetPasswordReqVO userReqVO); void resetPassword(MbrAuthResetPasswordReqVO userReqVO);
/**
*
* @param phone
* @param code
*/
void checkIfMobileMatchCodeAndDeleteCode(String phone,String code);
} }

View File

@ -40,7 +40,6 @@ import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
import javax.annotation.Resource; import javax.annotation.Resource;
import javax.validation.Valid;
import java.util.List; import java.util.List;
import java.util.Objects; import java.util.Objects;
@ -285,46 +284,30 @@ public class SysAuthServiceImpl implements SysAuthService {
} }
@Override @Override
public void updatePassword(Long userId, @Valid MbrAuthUpdatePasswordReqVO reqVO) { public void updatePassword(Long userId,MbrAuthUpdatePasswordReqVO reqVO) {
// 检验旧密码 // 检验旧密码
MbrUserDO userDO = checkOldPassword(userId, reqVO.getOldPassword()); MbrUserDO userDO = checkOldPassword(userId, reqVO.getOldPassword());
// 更新用户密码 // 更新用户密码
// TODO @宋天:不要更新整个对象哈 MbrUserDO mbrUserDO = MbrUserDO.builder().build();
userDO.setPassword(passwordEncoder.encode(reqVO.getPassword())); mbrUserDO.setId(userDO.getId());
userMapper.updateById(userDO); mbrUserDO.setPassword(passwordEncoder.encode(reqVO.getPassword()));
userMapper.updateById(mbrUserDO);
} }
@Override @Override
public void resetPassword(MbrAuthResetPasswordReqVO reqVO) { public void resetPassword(MbrAuthResetPasswordReqVO reqVO) {
// 根据验证码取出手机号,并查询用户 // 检验用户是否存在
String mobile = stringRedisTemplate.opsForValue().get(reqVO.getCode()); MbrUserDO userDO = checkUserIfExists(reqVO.getMobile());
MbrUserDO userDO = userMapper.selectByMobile(mobile);
if (userDO == null){
throw exception(USER_NOT_EXISTS);
}
// TODO @芋艿 这一步没必要检验验证码与手机是否匹配因为是根据验证码去redis中查找手机号然后根据手机号查询用户
// 也就是说 即便黑客以其他方式将验证码发送到自己手机上,最终还是会根据手机号查询用户然后进行重置密码的操作,不存在安全问题
// TODO @宋天:这块微信在讨论下哈~~~ // 使用验证码
smsCodeService.useSmsCode(reqVO.getMobile(),SysSmsSceneEnum.FORGET_MOBILE_BY_SMS.getScene(),reqVO.getCode(),getClientIP());
// 校验验证码
smsCodeService.useSmsCode(userDO.getMobile(), SysSmsSceneEnum.FORGET_MOBILE_BY_SMS.getScene(), reqVO.getCode(),getClientIP());
// 更新密码 // 更新密码
userDO.setPassword(passwordEncoder.encode(reqVO.getPassword())); MbrUserDO mbrUserDO = MbrUserDO.builder().build();
userMapper.updateById(userDO); mbrUserDO.setId(userDO.getId());
} mbrUserDO.setPassword(passwordEncoder.encode(reqVO.getPassword()));
userMapper.updateById(mbrUserDO);
@Override
public void checkIfMobileMatchCodeAndDeleteCode(String phone, String code) {
// 检验用户手机与验证码是否匹配
String mobile = stringRedisTemplate.opsForValue().get(code);
if (!phone.equals(mobile)){
throw exception(USER_CODE_FAILED);
}
// 销毁redis中此验证码
stringRedisTemplate.delete(code);
} }
/** /**
@ -347,6 +330,15 @@ public class SysAuthServiceImpl implements SysAuthService {
return user; return user;
} }
public MbrUserDO checkUserIfExists(String mobile) {
MbrUserDO user = userMapper.selectByMobile(mobile);
if (user == null) {
throw exception(USER_NOT_EXISTS);
}
return user;
}
private void createLogoutLog(Long userId, String username) { private void createLogoutLog(Long userId, String username) {
SysLoginLogCreateReqDTO reqDTO = new SysLoginLogCreateReqDTO(); SysLoginLogCreateReqDTO reqDTO = new SysLoginLogCreateReqDTO();
reqDTO.setLogType(SysLoginLogTypeEnum.LOGOUT_SELF.getType()); reqDTO.setLogType(SysLoginLogTypeEnum.LOGOUT_SELF.getType());

View File

@ -2,7 +2,7 @@ package cn.iocoder.yudao.userserver.modules.system.service.sms;
import cn.iocoder.yudao.framework.common.exception.ServiceException; import cn.iocoder.yudao.framework.common.exception.ServiceException;
import cn.iocoder.yudao.framework.common.validation.Mobile; import cn.iocoder.yudao.framework.common.validation.Mobile;
import cn.iocoder.yudao.userserver.modules.system.controller.auth.vo.SysAuthSendSmsReqVO; import cn.iocoder.yudao.userserver.modules.system.dal.dataobject.sms.SysSmsCodeDO;
import cn.iocoder.yudao.userserver.modules.system.enums.sms.SysSmsSceneEnum; import cn.iocoder.yudao.userserver.modules.system.enums.sms.SysSmsSceneEnum;
/** /**
@ -15,33 +15,38 @@ public interface SysSmsCodeService {
/** /**
* *
* *
* @param mobile * @param mobile
* @param scene {@link SysSmsSceneEnum} * @param scene {@link SysSmsSceneEnum}
* @param createIp IP * @param createIp IP
*/ */
void sendSmsCode(@Mobile String mobile, Integer scene, String createIp); void sendSmsCode(@Mobile String mobile, Integer scene, String createIp);
/**
*
* @param reqVO
*/
void sendSmsNewCode(SysAuthSendSmsReqVO reqVO);
/** /**
* 使 * 使
* 使 * 使
* {@link ServiceException} * {@link ServiceException}
* *
* @param mobile * @param mobile
* @param scene * @param scene
* @param code * @param code
* @param usedIp 使 IP * @param usedIp 使 IP
*/ */
void useSmsCode(@Mobile String mobile, Integer scene, String code, String usedIp); void useSmsCode(@Mobile String mobile, Integer scene, String code, String usedIp);
/** /**
* id * id
*
* @param userId id * @param userId id
*/ */
void sendSmsCodeLogin(Long userId); void sendSmsCodeLogin(Long userId);
/**
*
* @param mobile
* @param code
* @param scene 使
* @return
*/
SysSmsCodeDO checkCodeIsExpired(String mobile, String code, Integer scene);
} }

View File

@ -4,20 +4,16 @@ import cn.hutool.core.map.MapUtil;
import cn.iocoder.yudao.coreservice.modules.member.dal.dataobject.user.MbrUserDO; import cn.iocoder.yudao.coreservice.modules.member.dal.dataobject.user.MbrUserDO;
import cn.iocoder.yudao.coreservice.modules.system.service.sms.SysSmsCoreService; import cn.iocoder.yudao.coreservice.modules.system.service.sms.SysSmsCoreService;
import cn.iocoder.yudao.userserver.modules.member.service.user.MbrUserService; import cn.iocoder.yudao.userserver.modules.member.service.user.MbrUserService;
import cn.iocoder.yudao.userserver.modules.system.controller.auth.vo.SysAuthSendSmsReqVO;
import cn.iocoder.yudao.userserver.modules.system.dal.dataobject.sms.SysSmsCodeDO; import cn.iocoder.yudao.userserver.modules.system.dal.dataobject.sms.SysSmsCodeDO;
import cn.iocoder.yudao.userserver.modules.system.dal.mysql.sms.SysSmsCodeMapper; import cn.iocoder.yudao.userserver.modules.system.dal.mysql.sms.SysSmsCodeMapper;
import cn.iocoder.yudao.userserver.modules.system.enums.sms.SysSmsSceneEnum; import cn.iocoder.yudao.userserver.modules.system.enums.sms.SysSmsSceneEnum;
import cn.iocoder.yudao.userserver.modules.system.enums.sms.SysSmsTemplateCodeConstants;
import cn.iocoder.yudao.userserver.modules.system.framework.sms.SmsCodeProperties; import cn.iocoder.yudao.userserver.modules.system.framework.sms.SmsCodeProperties;
import cn.iocoder.yudao.userserver.modules.system.service.sms.SysSmsCodeService; import cn.iocoder.yudao.userserver.modules.system.service.sms.SysSmsCodeService;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated; import org.springframework.validation.annotation.Validated;
import javax.annotation.Resource; import javax.annotation.Resource;
import java.util.Date; import java.util.Date;
import java.util.concurrent.TimeUnit;
import static cn.hutool.core.util.RandomUtil.randomInt; import static cn.hutool.core.util.RandomUtil.randomInt;
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
@ -33,11 +29,6 @@ import static cn.iocoder.yudao.userserver.modules.system.enums.SysErrorCodeConst
@Validated @Validated
public class SysSmsCodeServiceImpl implements SysSmsCodeService { public class SysSmsCodeServiceImpl implements SysSmsCodeService {
/**
* + redis
*/
private static final Long CODE_TIME = 10L;
@Resource @Resource
private SmsCodeProperties smsCodeProperties; private SmsCodeProperties smsCodeProperties;
@ -50,40 +41,38 @@ public class SysSmsCodeServiceImpl implements SysSmsCodeService {
@Resource @Resource
private SysSmsCoreService smsCoreService; private SysSmsCoreService smsCoreService;
@Resource
private StringRedisTemplate stringRedisTemplate;
@Override @Override
public void sendSmsCode(String mobile, Integer scene, String createIp) { public void sendSmsCode(String mobile, Integer scene, String createIp) {
// 创建验证码 // 创建验证码
String code = this.createSmsCode(mobile, scene, createIp); String code = this.createSmsCode(mobile, scene, createIp);
// 发送验证码
// TODO @宋天:这里可以拓展下 SysSmsSceneEnum支持设置对应的短信模板编号不同场景的短信文案是不同的)、是否要校验手机号已经注册。这样 Controller 就可以收口成一个接口了。相当于说,不同场景,不同策略
smsCoreService.sendSingleSmsToMember(mobile, null, SysSmsTemplateCodeConstants.USER_SMS_LOGIN,
MapUtil.of("code", code));
// 存储手机号与验证码到redis用于标记 // 获取发送模板
// TODO @宋天SysSmsCodeDO 表应该足够,无需增加额外的 redis 存储哇 String codeTemplate = SysSmsSceneEnum.getCodeByScene(scene);
// TODO @宋天Redis 相关的操作,不要散落到业务层,而是写一个它对应的 RedisDAO。这样实现业务与技术的解耦
// TODO @宋天:直接使用 code 作为 key会存在 2 个问题1code 可能会冲突多个手机号之间2缺少前缀。例如说 sms_code_${code} // 如果是更换手机号发送验证码,则需要检测手机号是否被注册
stringRedisTemplate.opsForValue().set(code,mobile,CODE_TIME, TimeUnit.MINUTES); if (SysSmsSceneEnum.CHANGE_MOBILE_BY_SMS.getScene().equals(scene)){
this.checkMobileIsRegister(mobile,scene);
}
// 发送验证码
smsCoreService.sendSingleSmsToMember(mobile, null, codeTemplate,
MapUtil.of("code", code));
} }
@Override public void checkMobileIsRegister(String mobile, Integer scene) {
public void sendSmsNewCode(SysAuthSendSmsReqVO reqVO) {
// 检测手机号是否已被使用 // 检测手机号是否已被使用
MbrUserDO userByMobile = mbrUserService.getUserByMobile(reqVO.getMobile()); MbrUserDO userByMobile = mbrUserService.getUserByMobile(mobile);
if (userByMobile != null){ if (userByMobile != null){
throw exception(USER_SMS_CODE_IS_EXISTS); throw exception(USER_SMS_CODE_IS_EXISTS);
} }
// 发送短信 // 发送短信
this.sendSmsCode(reqVO.getMobile(),reqVO.getScene(),getClientIP()); this.sendSmsCode(mobile,scene,getClientIP());
} }
private String createSmsCode(String mobile, Integer scene, String ip) { private String createSmsCode(String mobile, Integer scene, String ip) {
// 校验是否可以发送验证码,不用筛选场景 // 校验是否可以发送验证码,不用筛选场景
SysSmsCodeDO lastSmsCode = smsCodeMapper.selectLastByMobile(mobile, null); SysSmsCodeDO lastSmsCode = smsCodeMapper.selectLastByMobile(mobile, null,null);
if (lastSmsCode != null) { if (lastSmsCode != null) {
if (lastSmsCode.getTodayIndex() >= smsCodeProperties.getSendMaximumQuantityPerDay()) { // 超过当天发送的上限。 if (lastSmsCode.getTodayIndex() >= smsCodeProperties.getSendMaximumQuantityPerDay()) { // 超过当天发送的上限。
throw exception(USER_SMS_CODE_EXCEED_SEND_MAXIMUM_QUANTITY_PER_DAY); throw exception(USER_SMS_CODE_EXCEED_SEND_MAXIMUM_QUANTITY_PER_DAY);
@ -107,21 +96,14 @@ public class SysSmsCodeServiceImpl implements SysSmsCodeService {
@Override @Override
public void useSmsCode(String mobile, Integer scene, String code, String usedIp) { public void useSmsCode(String mobile, Integer scene, String code, String usedIp) {
// 校验验证码
SysSmsCodeDO lastSmsCode = smsCodeMapper.selectLastByMobile(mobile, scene); // 检测验证码是否有效
if (lastSmsCode == null) { // 若验证码不存在,抛出异常 SysSmsCodeDO lastSmsCode = this.checkCodeIsExpired(mobile, code, scene);
throw exception(USER_SMS_CODE_NOT_FOUND);
} // 判断验证码是否已被使用
if (System.currentTimeMillis() - lastSmsCode.getCreateTime().getTime() if (Boolean.TRUE.equals(lastSmsCode.getUsed())) {
>= smsCodeProperties.getExpireTimes().toMillis()) { // 验证码已过期
throw exception(USER_SMS_CODE_EXPIRED);
}
if (lastSmsCode.getUsed()) { // 验证码已使用
throw exception(USER_SMS_CODE_USED); throw exception(USER_SMS_CODE_USED);
} }
if (!lastSmsCode.getCode().equals(code)) {
throw exception(USER_SMS_CODE_NOT_CORRECT);
}
// 使用验证码 // 使用验证码
smsCodeMapper.updateById(SysSmsCodeDO.builder().id(lastSmsCode.getId()) smsCodeMapper.updateById(SysSmsCodeDO.builder().id(lastSmsCode.getId())
@ -138,4 +120,22 @@ public class SysSmsCodeServiceImpl implements SysSmsCodeService {
this.sendSmsCode(user.getMobile(),SysSmsSceneEnum.CHANGE_MOBILE_BY_SMS.getScene(), getClientIP()); this.sendSmsCode(user.getMobile(),SysSmsSceneEnum.CHANGE_MOBILE_BY_SMS.getScene(), getClientIP());
} }
@Override
public SysSmsCodeDO checkCodeIsExpired(String mobile, String code, Integer scene) {
// 校验验证码
SysSmsCodeDO lastSmsCode = smsCodeMapper.selectLastByMobile(mobile,code,scene);
// 若验证码不存在,抛出异常
if (lastSmsCode == null) {
throw exception(USER_SMS_CODE_NOT_FOUND);
}
if (System.currentTimeMillis() - lastSmsCode.getCreateTime().getTime()
>= smsCodeProperties.getExpireTimes().toMillis()) { // 验证码已过期
throw exception(USER_SMS_CODE_EXPIRED);
}
return lastSmsCode;
}
} }

View File

@ -1,62 +0,0 @@
package cn.iocoder.yudao.userserver.modules.member.controller;
import cn.iocoder.yudao.userserver.modules.member.controller.user.SysUserProfileController;
import cn.iocoder.yudao.userserver.modules.member.service.user.MbrUserService;
import cn.iocoder.yudao.userserver.modules.system.service.sms.SysSmsCodeService;
import org.junit.Before;
import org.junit.Ignore;
import org.junit.Test;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.springframework.http.MediaType;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.result.MockMvcResultHandlers;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
/**
* {@link SysUserProfileController}
*
* @author
*/
// TODO @宋天controller 的单测可以不写哈,因为收益太低了。未来我们做 qa 自动化测试
public class SysUserProfileControllerTest {
private MockMvc mockMvc;
@InjectMocks
private SysUserProfileController sysUserProfileController;
@Mock
private MbrUserService userService;
@Mock
private SysSmsCodeService smsCodeService;
@Before // TODO @宋天:使用 junit5 哈
public void setup() {
// 初始化
MockitoAnnotations.openMocks(this);
// 构建mvc环境
mockMvc = MockMvcBuilders.standaloneSetup(sysUserProfileController).build();
}
@Test
@Ignore
public void testUpdateMobile_success() throws Exception {
//模拟接口调用
this.mockMvc.perform(post("/system/user/profile/update-mobile")
.contentType(MediaType.APPLICATION_JSON_VALUE)
.content("{\"mobile\":\"15819844280\",\"code\":\"123456\"}}"))
.andExpect(status().isOk())
.andDo(MockMvcResultHandlers.print());
// TODO @宋天:方法的结尾,不用空行哈
}
}

View File

@ -1,5 +1,6 @@
package cn.iocoder.yudao.userserver.modules.member.service; package cn.iocoder.yudao.userserver.modules.member.service;
import cn.hutool.core.util.RandomUtil;
import cn.iocoder.yudao.coreservice.modules.infra.service.file.InfFileCoreService; import cn.iocoder.yudao.coreservice.modules.infra.service.file.InfFileCoreService;
import cn.iocoder.yudao.coreservice.modules.member.dal.dataobject.user.MbrUserDO; import cn.iocoder.yudao.coreservice.modules.member.dal.dataobject.user.MbrUserDO;
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
@ -10,8 +11,7 @@ import cn.iocoder.yudao.userserver.modules.member.controller.user.vo.MbrUserInfo
import cn.iocoder.yudao.userserver.modules.member.controller.user.vo.MbrUserUpdateMobileReqVO; import cn.iocoder.yudao.userserver.modules.member.controller.user.vo.MbrUserUpdateMobileReqVO;
import cn.iocoder.yudao.userserver.modules.member.dal.mysql.user.MbrUserMapper; import cn.iocoder.yudao.userserver.modules.member.dal.mysql.user.MbrUserMapper;
import cn.iocoder.yudao.userserver.modules.member.service.user.impl.MbrUserServiceImpl; import cn.iocoder.yudao.userserver.modules.member.service.user.impl.MbrUserServiceImpl;
import cn.iocoder.yudao.userserver.modules.system.controller.auth.vo.SysAuthSendSmsReqVO; import cn.iocoder.yudao.userserver.modules.system.dal.dataobject.sms.SysSmsCodeDO;
import cn.iocoder.yudao.userserver.modules.system.enums.sms.SysSmsSceneEnum;
import cn.iocoder.yudao.userserver.modules.system.service.auth.impl.SysAuthServiceImpl; import cn.iocoder.yudao.userserver.modules.system.service.auth.impl.SysAuthServiceImpl;
import cn.iocoder.yudao.userserver.modules.system.service.sms.SysSmsCodeService; import cn.iocoder.yudao.userserver.modules.system.service.sms.SysSmsCodeService;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
@ -27,6 +27,7 @@ import java.util.function.Consumer;
import static cn.hutool.core.util.RandomUtil.*; import static cn.hutool.core.util.RandomUtil.*;
import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomPojo; import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomPojo;
import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomString; import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomString;
import static cn.iocoder.yudao.userserver.modules.system.enums.sms.SysSmsSceneEnum.CHANGE_MOBILE_BY_SMS;
import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.mockito.Mockito.*; import static org.mockito.Mockito.*;
@ -115,23 +116,24 @@ public class MbrUserServiceImplTest extends BaseDbAndRedisUnitTest {
userDO.setMobile(oldMobile); userDO.setMobile(oldMobile);
userMapper.insert(userDO); userMapper.insert(userDO);
// 验证旧手机
sysSmsCodeService.sendSmsCodeLogin(userDO.getId());
// 验证旧手机验证码是否正确 // 旧手机和旧验证码
sysSmsCodeService.useSmsCode(oldMobile,SysSmsSceneEnum.CHANGE_MOBILE_BY_SMS.getScene(),"123","1.1.1.1"); SysSmsCodeDO codeDO = new SysSmsCodeDO();
// 验证新手机 String oldCode = RandomUtil.randomString(4);
SysAuthSendSmsReqVO smsReqVO = new SysAuthSendSmsReqVO(); codeDO.setMobile(userDO.getMobile());
smsReqVO.setMobile(oldMobile); codeDO.setCode(oldCode);
smsReqVO.setScene(SysSmsSceneEnum.CHANGE_MOBILE_BY_SMS.getScene()); codeDO.setScene(CHANGE_MOBILE_BY_SMS.getScene());
sysSmsCodeService.sendSmsNewCode(smsReqVO); codeDO.setUsed(Boolean.FALSE);
when(sysSmsCodeService.checkCodeIsExpired(codeDO.getMobile(),codeDO.getCode(),codeDO.getScene())).thenReturn(codeDO);
// 更新手机号 // 更新手机号
String newMobile = randomNumbers(11); String newMobile = randomNumbers(11);
String code = randomNumbers(4); String newCode = randomNumbers(4);
MbrUserUpdateMobileReqVO reqVO = new MbrUserUpdateMobileReqVO(); MbrUserUpdateMobileReqVO reqVO = new MbrUserUpdateMobileReqVO();
reqVO.setMobile(newMobile); reqVO.setMobile(newMobile);
reqVO.setCode(code); reqVO.setCode(newCode);
reqVO.setOldMobile(oldMobile);
reqVO.setOldCode(oldCode);
mbrUserService.updateMobile(userDO.getId(),reqVO); mbrUserService.updateMobile(userDO.getId(),reqVO);
assertEquals(mbrUserService.getUser(userDO.getId()).getMobile(),newMobile); assertEquals(mbrUserService.getUser(userDO.getId()).getMobile(),newMobile);

View File

@ -1,68 +0,0 @@
package cn.iocoder.yudao.userserver.modules.system.controller;
import cn.iocoder.yudao.coreservice.modules.system.service.social.SysSocialCoreService;
import cn.iocoder.yudao.userserver.modules.system.controller.auth.SysAuthController;
import cn.iocoder.yudao.userserver.modules.system.service.auth.SysAuthService;
import cn.iocoder.yudao.userserver.modules.system.service.sms.SysSmsCodeService;
import org.junit.Before;
import org.junit.Test;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.springframework.http.MediaType;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.result.MockMvcResultHandlers;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
/**
* {@link SysAuthController}
*
* @author
*/
public class SysAuthControllerTest {
private MockMvc mockMvc;
@InjectMocks
private SysAuthController sysAuthController;
@Mock
private SysAuthService authService;
@Mock
private SysSmsCodeService smsCodeService;
@Mock
private SysSocialCoreService socialService;
@Before
public void setup() {
// 初始化
MockitoAnnotations.openMocks(this);
// 构建mvc环境
mockMvc = MockMvcBuilders.standaloneSetup(sysAuthController).build();
}
@Test
public void testResetPassword_success() throws Exception {
// 模拟接口调用
this.mockMvc.perform(post("/reset-password")
.contentType(MediaType.APPLICATION_JSON)
.content("{\"password\":\"1123\",\"code\":\"123456\"}}"))
.andExpect(status().isOk())
.andDo(MockMvcResultHandlers.print());
}
@Test
public void testUpdatePassword_success() throws Exception {
// 模拟接口调用
this.mockMvc.perform(post("/update-password")
.contentType(MediaType.APPLICATION_JSON)
.content("{\"password\":\"1123\",\"code\":\"123456\",\"oldPassword\":\"1123\"}}"))
.andExpect(status().isOk())
.andDo(MockMvcResultHandlers.print());
}
}

View File

@ -23,7 +23,6 @@ import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.security.crypto.password.PasswordEncoder;
import javax.annotation.Resource; import javax.annotation.Resource;
import java.util.concurrent.TimeUnit;
import java.util.function.Consumer; import java.util.function.Consumer;
import static cn.hutool.core.util.RandomUtil.randomEle; import static cn.hutool.core.util.RandomUtil.randomEle;
@ -99,17 +98,15 @@ public class SysAuthServiceTest extends BaseDbAndRedisUnitTest {
// 随机验证码 // 随机验证码
String code = randomNumbers(4); String code = randomNumbers(4);
MbrAuthResetPasswordReqVO reqVO = MbrAuthResetPasswordReqVO.builder()
.password(password)
.code(code)
.build();
// 放入code+手机号
stringRedisTemplate.opsForValue().set(code,userDO.getMobile(),10, TimeUnit.MINUTES);
// mock // mock
when(passwordEncoder.encode(password)).thenReturn(password); when(passwordEncoder.encode(password)).thenReturn(password);
// 更新用户密码 // 更新用户密码
MbrAuthResetPasswordReqVO reqVO = new MbrAuthResetPasswordReqVO();
reqVO.setMobile(userDO.getMobile());
reqVO.setPassword(password);
reqVO.setCode(code);
authService.resetPassword(reqVO); authService.resetPassword(reqVO);
assertEquals(mbrUserMapper.selectById(userDO.getId()).getPassword(),password); assertEquals(mbrUserMapper.selectById(userDO.getId()).getPassword(),password);
} }