update 新增接口:修改手机,修改密码,忘记密码
parent
c84e19e14e
commit
8e0569ee54
|
@ -91,6 +91,13 @@
|
|||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<!--单元测试相关-->
|
||||
<dependency>
|
||||
<groupId>junit</groupId>
|
||||
<artifactId>junit</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<!-- 工具类相关 -->
|
||||
|
||||
</dependencies>
|
||||
|
|
|
@ -5,6 +5,9 @@ import cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil;
|
|||
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
|
||||
import cn.iocoder.yudao.framework.security.core.annotations.PreAuthenticated;
|
||||
import cn.iocoder.yudao.userserver.modules.member.service.user.MbrUserService;
|
||||
import cn.iocoder.yudao.userserver.modules.member.controller.user.vo.MbrUserUpdateMobileReqVO;
|
||||
import cn.iocoder.yudao.userserver.modules.system.enums.sms.SysSmsSceneEnum;
|
||||
import cn.iocoder.yudao.userserver.modules.system.service.sms.SysSmsCodeService;
|
||||
import io.swagger.annotations.Api;
|
||||
import io.swagger.annotations.ApiOperation;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
@ -13,10 +16,12 @@ import org.springframework.web.bind.annotation.*;
|
|||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import javax.validation.Valid;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
|
||||
import static cn.iocoder.yudao.framework.common.util.servlet.ServletUtils.getClientIP;
|
||||
import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId;
|
||||
import static cn.iocoder.yudao.userserver.modules.member.enums.MbrErrorCodeConstants.FILE_IS_EMPTY;
|
||||
|
||||
|
@ -30,6 +35,9 @@ public class SysUserProfileController {
|
|||
@Resource
|
||||
private MbrUserService userService;
|
||||
|
||||
@Resource
|
||||
private SysSmsCodeService smsCodeService;
|
||||
|
||||
@PutMapping("/update-nickname")
|
||||
@ApiOperation("修改用户昵称")
|
||||
@PreAuthenticated
|
||||
|
@ -56,5 +64,17 @@ public class SysUserProfileController {
|
|||
return success(userService.getUserInfo(getLoginUserId()));
|
||||
}
|
||||
|
||||
|
||||
@PostMapping("/update-mobile")
|
||||
@ApiOperation(value = "修改用户手机")
|
||||
@PreAuthenticated
|
||||
public CommonResult<Boolean> updateMobile(@RequestBody @Valid MbrUserUpdateMobileReqVO reqVO) {
|
||||
// 校验验证码
|
||||
smsCodeService.useSmsCode(reqVO.getMobile(),SysSmsSceneEnum.CHANGE_MOBILE_BY_SMS.getScene(), reqVO.getCode(),getClientIP());
|
||||
|
||||
userService.updateMobile(getLoginUserId(), reqVO);
|
||||
return success(true);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,35 @@
|
|||
package cn.iocoder.yudao.userserver.modules.member.controller.user.vo;
|
||||
|
||||
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.NotEmpty;
|
||||
import javax.validation.constraints.Pattern;
|
||||
|
||||
@ApiModel("修改手机 Request VO")
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Builder
|
||||
public class MbrUserUpdateMobileReqVO {
|
||||
|
||||
@ApiModelProperty(value = "手机验证码", required = true, example = "1024")
|
||||
@NotEmpty(message = "手机验证码不能为空")
|
||||
@Length(min = 4, max = 6, message = "手机验证码长度为 4-6 位")
|
||||
@Pattern(regexp = "^[0-9]+$", message = "手机验证码必须都是数字")
|
||||
private String code;
|
||||
|
||||
|
||||
@ApiModelProperty(value = "手机号",required = true,example = "15823654487")
|
||||
@NotBlank(message = "手机号不能为空")
|
||||
@Length(min = 8, max = 11, message = "手机号码长度为 8-11 位")
|
||||
@Pattern(regexp = "^1[3-9]\\d{9}$", message = "手机号格式错误")
|
||||
private String mobile;
|
||||
|
||||
}
|
|
@ -3,6 +3,7 @@ package cn.iocoder.yudao.userserver.modules.member.service.user;
|
|||
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.validation.Mobile;
|
||||
import cn.iocoder.yudao.userserver.modules.member.controller.user.vo.MbrUserUpdateMobileReqVO;
|
||||
|
||||
import java.io.InputStream;
|
||||
|
||||
|
@ -69,4 +70,11 @@ public interface MbrUserService {
|
|||
*/
|
||||
MbrUserInfoRespVO getUserInfo(Long userId);
|
||||
|
||||
/**
|
||||
* 修改手机
|
||||
* @param userId 用户id
|
||||
* @param reqVO 请求实体
|
||||
*/
|
||||
void updateMobile(Long userId, MbrUserUpdateMobileReqVO reqVO);
|
||||
|
||||
}
|
||||
|
|
|
@ -6,8 +6,10 @@ import cn.iocoder.yudao.coreservice.modules.infra.service.file.InfFileCoreServic
|
|||
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.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.service.user.MbrUserService;
|
||||
import cn.iocoder.yudao.userserver.modules.system.service.auth.SysAuthService;
|
||||
import com.google.common.annotations.VisibleForTesting;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.security.crypto.password.PasswordEncoder;
|
||||
|
@ -40,6 +42,9 @@ public class MbrUserServiceImpl implements MbrUserService {
|
|||
@Resource
|
||||
private PasswordEncoder passwordEncoder;
|
||||
|
||||
@Resource
|
||||
private SysAuthService sysAuthService;
|
||||
|
||||
@Override
|
||||
public MbrUserDO getUserByMobile(String mobile) {
|
||||
return userMapper.selectByMobile(mobile);
|
||||
|
@ -116,6 +121,17 @@ public class MbrUserServiceImpl implements MbrUserService {
|
|||
return userResp;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateMobile(Long userId, MbrUserUpdateMobileReqVO reqVO) {
|
||||
// 检测用户是否存在
|
||||
MbrUserDO userDO = checkUserExists(userId);
|
||||
// 检测手机与验证码是否匹配
|
||||
sysAuthService.checkIfMobileMatchCodeAndDeleteCode(userDO.getMobile(),reqVO.getCode());
|
||||
// 更新用户手机
|
||||
userDO.setMobile(reqVO.getMobile());
|
||||
userMapper.updateById(userDO);
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
public MbrUserDO checkUserExists(Long id) {
|
||||
if (id == null) {
|
||||
|
|
|
@ -3,7 +3,9 @@ package cn.iocoder.yudao.userserver.modules.system.controller.auth;
|
|||
import cn.iocoder.yudao.coreservice.modules.system.service.social.SysSocialService;
|
||||
import cn.iocoder.yudao.framework.common.enums.UserTypeEnum;
|
||||
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
|
||||
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.enums.sms.SysSmsSceneEnum;
|
||||
import cn.iocoder.yudao.userserver.modules.system.service.auth.SysAuthService;
|
||||
import cn.iocoder.yudao.userserver.modules.system.service.sms.SysSmsCodeService;
|
||||
import com.alibaba.fastjson.JSON;
|
||||
|
@ -56,16 +58,47 @@ public class SysAuthController {
|
|||
}
|
||||
|
||||
@PostMapping("/send-sms-code")
|
||||
@ApiOperation("发送手机验证码")
|
||||
@ApiOperation(value = "发送手机验证码",notes = "不检测该手机号是否已被注册")
|
||||
public CommonResult<Boolean> sendSmsCode(@RequestBody @Valid SysAuthSendSmsReqVO reqVO) {
|
||||
smsCodeService.sendSmsCode(reqVO.getMobile(), reqVO.getScene(), getClientIP());
|
||||
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")
|
||||
@ApiOperation(value = "向已登录用户发送验证码",notes = "修改手机时验证原手机号使用")
|
||||
public CommonResult<Boolean> sendSmsCodeLogin() {
|
||||
smsCodeService.sendSmsCodeLogin(getLoginUserId());
|
||||
return success(true);
|
||||
}
|
||||
|
||||
@PostMapping("/reset-password")
|
||||
@ApiOperation(value = "重置密码", notes = "用户忘记密码时使用")
|
||||
public CommonResult<Boolean> resetPassword(@RequestBody @Valid MbrAuthResetPasswordReqVO reqVO) {
|
||||
return null;
|
||||
public CommonResult<Boolean> resetPassword(@RequestBody @Validated(MbrAuthResetPasswordReqVO.resetPasswordValidView.class) MbrAuthResetPasswordReqVO reqVO) {
|
||||
authService.resetPassword(reqVO);
|
||||
return success(true);
|
||||
}
|
||||
|
||||
@PostMapping("/update-password")
|
||||
@ApiOperation(value = "修改用户密码",notes = "用户修改密码时使用")
|
||||
@PreAuthenticated
|
||||
public CommonResult<Boolean> updatePassword(@RequestBody @Validated(MbrAuthResetPasswordReqVO.updatePasswordValidView.class) MbrAuthResetPasswordReqVO reqVO) {
|
||||
authService.updatePassword(getLoginUserId(), reqVO);
|
||||
return success(true);
|
||||
}
|
||||
|
||||
@PostMapping("/check-sms-code")
|
||||
@ApiOperation(value = "校验验证码是否正确")
|
||||
@PreAuthenticated
|
||||
public CommonResult<Boolean> checkSmsCode(@RequestBody @Valid SysAuthSmsLoginReqVO reqVO) {
|
||||
smsCodeService.useSmsCode(reqVO.getMobile(),SysSmsSceneEnum.CHECK_CODE_BY_SMS.getScene(),reqVO.getCode(),getClientIP());
|
||||
return success(true);
|
||||
}
|
||||
|
||||
// ========== 社交登录相关 ==========
|
||||
|
|
|
@ -8,6 +8,7 @@ import lombok.Data;
|
|||
import lombok.NoArgsConstructor;
|
||||
import org.hibernate.validator.constraints.Length;
|
||||
|
||||
import javax.validation.constraints.NotBlank;
|
||||
import javax.validation.constraints.NotEmpty;
|
||||
import javax.validation.constraints.Pattern;
|
||||
|
||||
|
@ -18,15 +19,31 @@ import javax.validation.constraints.Pattern;
|
|||
@Builder
|
||||
public class MbrAuthResetPasswordReqVO {
|
||||
|
||||
/**
|
||||
* 修改密码校验规则
|
||||
*/
|
||||
public interface updatePasswordValidView {
|
||||
}
|
||||
|
||||
/**
|
||||
* 忘记密码校验规则
|
||||
*/
|
||||
public interface resetPasswordValidView {
|
||||
}
|
||||
|
||||
@ApiModelProperty(value = "用户旧密码", required = true, example = "123456")
|
||||
@NotBlank(message = "旧密码不能为空",groups = updatePasswordValidView.class)
|
||||
@Length(min = 4, max = 16, message = "密码长度为 4-16 位")
|
||||
private String oldPassword;
|
||||
|
||||
@ApiModelProperty(value = "新密码", required = true, example = "buzhidao")
|
||||
@NotEmpty(message = "新密码不能为空")
|
||||
@NotEmpty(message = "新密码不能为空",groups = {updatePasswordValidView.class,resetPasswordValidView.class})
|
||||
@Length(min = 4, max = 16, message = "密码长度为 4-16 位")
|
||||
private String password;
|
||||
|
||||
@ApiModelProperty(value = "手机验证码", required = true, example = "1024")
|
||||
@NotEmpty(message = "手机验证码不能为空")
|
||||
@NotEmpty(message = "手机验证码不能为空",groups = resetPasswordValidView.class)
|
||||
@Length(min = 4, max = 6, message = "手机验证码长度为 4-6 位")
|
||||
@Pattern(regexp = "^[0-9]+$", message = "手机验证码必须都是数字")
|
||||
private String code;
|
||||
|
||||
}
|
||||
|
|
|
@ -23,7 +23,10 @@ public interface SysErrorCodeConstants {
|
|||
ErrorCode USER_SMS_CODE_NOT_CORRECT = new ErrorCode(1005001003, "验证码不正确");
|
||||
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_IS_EXISTS = new ErrorCode(1005001006, "手机号已被使用");
|
||||
|
||||
// ========== 用户模块 1005002000 ==========
|
||||
ErrorCode USER_NOT_EXISTS = new ErrorCode(1005002001, "用户不存在");
|
||||
ErrorCode USER_CODE_FAILED = new ErrorCode(1005002002, "验证码不匹配");
|
||||
ErrorCode USER_PASSWORD_FAILED = new ErrorCode(1005002003, "密码校验失败");
|
||||
}
|
||||
|
|
|
@ -17,7 +17,9 @@ public enum SysSmsSceneEnum implements IntArrayValuable {
|
|||
|
||||
LOGIN_BY_SMS(1, "手机号登陆"),
|
||||
CHANGE_MOBILE_BY_SMS(2, "更换手机号"),
|
||||
;
|
||||
FORGET_MOBILE_BY_SMS(3, "忘记密码"),
|
||||
CHECK_CODE_BY_SMS(4, "审核验证码"),
|
||||
;
|
||||
|
||||
public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(SysSmsSceneEnum::getScene).toArray();
|
||||
|
||||
|
|
|
@ -63,4 +63,23 @@ public interface SysAuthService extends SecurityAuthFrameworkService {
|
|||
*/
|
||||
void socialBind(Long userId, @Valid MbrAuthSocialBindReqVO reqVO);
|
||||
|
||||
/**
|
||||
* 修改用户密码
|
||||
* @param userId 用户id
|
||||
* @param userReqVO 用户请求实体类
|
||||
*/
|
||||
void updatePassword(Long userId, MbrAuthResetPasswordReqVO userReqVO);
|
||||
|
||||
/**
|
||||
* 忘记密码
|
||||
* @param userReqVO 用户请求实体类
|
||||
*/
|
||||
void resetPassword(MbrAuthResetPasswordReqVO userReqVO);
|
||||
|
||||
/**
|
||||
* 检测手机与验证码是否匹配
|
||||
* @param phone 手机号
|
||||
* @param code 验证码
|
||||
*/
|
||||
void checkIfMobileMatchCodeAndDeleteCode(String phone,String code);
|
||||
}
|
||||
|
|
|
@ -15,15 +15,19 @@ import cn.iocoder.yudao.framework.common.enums.UserTypeEnum;
|
|||
import cn.iocoder.yudao.framework.common.util.monitor.TracerUtils;
|
||||
import cn.iocoder.yudao.framework.common.util.servlet.ServletUtils;
|
||||
import cn.iocoder.yudao.framework.security.core.LoginUser;
|
||||
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.system.controller.auth.vo.*;
|
||||
import cn.iocoder.yudao.userserver.modules.system.convert.auth.SysAuthConvert;
|
||||
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.sms.SysSmsCodeService;
|
||||
import com.google.common.annotations.VisibleForTesting;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import me.zhyd.oauth.model.AuthUser;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.annotation.Lazy;
|
||||
import org.springframework.data.redis.core.StringRedisTemplate;
|
||||
import org.springframework.security.authentication.AuthenticationManager;
|
||||
import org.springframework.security.authentication.BadCredentialsException;
|
||||
import org.springframework.security.authentication.DisabledException;
|
||||
|
@ -32,6 +36,7 @@ import org.springframework.security.core.Authentication;
|
|||
import org.springframework.security.core.AuthenticationException;
|
||||
import org.springframework.security.core.userdetails.UserDetails;
|
||||
import org.springframework.security.core.userdetails.UsernameNotFoundException;
|
||||
import org.springframework.security.crypto.password.PasswordEncoder;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
|
@ -40,6 +45,7 @@ import java.util.List;
|
|||
import java.util.Objects;
|
||||
|
||||
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
|
||||
import static cn.iocoder.yudao.framework.common.util.servlet.ServletUtils.getClientIP;
|
||||
import static cn.iocoder.yudao.userserver.modules.system.enums.SysErrorCodeConstants.*;
|
||||
|
||||
/**
|
||||
|
@ -65,6 +71,13 @@ public class SysAuthServiceImpl implements SysAuthService {
|
|||
private SysUserSessionCoreService userSessionCoreService;
|
||||
@Resource
|
||||
private SysSocialService socialService;
|
||||
@Resource
|
||||
private StringRedisTemplate stringRedisTemplate;
|
||||
@Resource
|
||||
private PasswordEncoder passwordEncoder;
|
||||
@Resource
|
||||
private MbrUserMapper userMapper;
|
||||
|
||||
private static final UserTypeEnum userTypeEnum = UserTypeEnum.MEMBER;
|
||||
|
||||
@Override
|
||||
|
@ -200,12 +213,12 @@ public class SysAuthServiceImpl implements SysAuthService {
|
|||
}
|
||||
reqDTO.setUsername(mobile);
|
||||
reqDTO.setUserAgent(ServletUtils.getUserAgent());
|
||||
reqDTO.setUserIp(ServletUtils.getClientIP());
|
||||
reqDTO.setUserIp(getClientIP());
|
||||
reqDTO.setResult(loginResult.getResult());
|
||||
loginLogCoreService.createLoginLog(reqDTO);
|
||||
// 更新最后登录时间
|
||||
if (user != null && Objects.equals(SysLoginResultEnum.SUCCESS.getResult(), loginResult.getResult())) {
|
||||
userService.updateUserLogin(user.getId(), ServletUtils.getClientIP());
|
||||
userService.updateUserLogin(user.getId(), getClientIP());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -266,6 +279,66 @@ public class SysAuthServiceImpl implements SysAuthService {
|
|||
this.createLogoutLog(loginUser.getId(), loginUser.getUsername());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updatePassword(Long userId, MbrAuthResetPasswordReqVO reqVO) {
|
||||
// 检验旧密码
|
||||
MbrUserDO userDO = checkOldPassword(userId, reqVO.getOldPassword());
|
||||
|
||||
// 更新用户密码
|
||||
userDO.setPassword(passwordEncoder.encode(reqVO.getPassword()));
|
||||
userMapper.updateById(userDO);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void resetPassword(MbrAuthResetPasswordReqVO reqVO) {
|
||||
// 根据验证码取出手机号,并查询用户
|
||||
String mobile = stringRedisTemplate.opsForValue().get(reqVO.getCode());
|
||||
MbrUserDO userDO = userMapper.selectByMobile(mobile);
|
||||
if (userDO == null){
|
||||
throw exception(USER_NOT_EXISTS);
|
||||
}
|
||||
// TODO @芋艿 这一步没必要检验验证码与手机是否匹配,因为是根据验证码去redis中查找手机号,然后根据手机号查询用户
|
||||
// 也就是说 即便黑客以其他方式将验证码发送到自己手机上,最终还是会根据手机号查询用户然后进行重置密码的操作,不存在安全问题
|
||||
|
||||
// 校验验证码
|
||||
smsCodeService.useSmsCode(userDO.getMobile(), SysSmsSceneEnum.FORGET_MOBILE_BY_SMS.getScene(), reqVO.getCode(),getClientIP());
|
||||
|
||||
// 更新密码
|
||||
userDO.setPassword(passwordEncoder.encode(reqVO.getPassword()));
|
||||
userMapper.updateById(userDO);
|
||||
}
|
||||
|
||||
@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);
|
||||
}
|
||||
|
||||
/**
|
||||
* 校验旧密码
|
||||
*
|
||||
* @param id 用户 id
|
||||
* @param oldPassword 旧密码
|
||||
* @return MbrUserDO 用户实体
|
||||
*/
|
||||
@VisibleForTesting
|
||||
public MbrUserDO checkOldPassword(Long id, String oldPassword) {
|
||||
MbrUserDO user = userMapper.selectById(id);
|
||||
if (user == null) {
|
||||
throw exception(USER_NOT_EXISTS);
|
||||
}
|
||||
// 参数:未加密密码,编码后的密码
|
||||
if (!passwordEncoder.matches(oldPassword,user.getPassword())) {
|
||||
throw exception(USER_PASSWORD_FAILED);
|
||||
}
|
||||
return user;
|
||||
}
|
||||
|
||||
private void createLogoutLog(Long userId, String username) {
|
||||
SysLoginLogCreateReqDTO reqDTO = new SysLoginLogCreateReqDTO();
|
||||
reqDTO.setLogType(SysLoginLogTypeEnum.LOGOUT_SELF.getType());
|
||||
|
@ -274,7 +347,7 @@ public class SysAuthServiceImpl implements SysAuthService {
|
|||
reqDTO.setUserType(userTypeEnum.getValue());
|
||||
reqDTO.setUsername(username);
|
||||
reqDTO.setUserAgent(ServletUtils.getUserAgent());
|
||||
reqDTO.setUserIp(ServletUtils.getClientIP());
|
||||
reqDTO.setUserIp(getClientIP());
|
||||
reqDTO.setResult(SysLoginResultEnum.SUCCESS.getResult());
|
||||
loginLogCoreService.createLoginLog(reqDTO);
|
||||
}
|
||||
|
|
|
@ -2,6 +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.validation.Mobile;
|
||||
import cn.iocoder.yudao.userserver.modules.system.controller.auth.vo.SysAuthSendSmsReqVO;
|
||||
import cn.iocoder.yudao.userserver.modules.system.enums.sms.SysSmsSceneEnum;
|
||||
|
||||
/**
|
||||
|
@ -20,6 +21,12 @@ public interface SysSmsCodeService {
|
|||
*/
|
||||
void sendSmsCode(@Mobile String mobile, Integer scene, String createIp);
|
||||
|
||||
/**
|
||||
* 发送短信验证码,并检测手机号是否已被注册
|
||||
* @param reqVO 请求实体
|
||||
*/
|
||||
void sendSmsNewCode(SysAuthSendSmsReqVO reqVO);
|
||||
|
||||
/**
|
||||
* 验证短信验证码,并进行使用
|
||||
* 如果正确,则将验证码标记成已使用
|
||||
|
@ -32,4 +39,9 @@ public interface SysSmsCodeService {
|
|||
*/
|
||||
void useSmsCode(@Mobile String mobile, Integer scene, String code, String usedIp);
|
||||
|
||||
/**
|
||||
* 根据用户id发送验证码
|
||||
* @param userId 用户id
|
||||
*/
|
||||
void sendSmsCodeLogin(Long userId);
|
||||
}
|
||||
|
|
|
@ -1,20 +1,27 @@
|
|||
package cn.iocoder.yudao.userserver.modules.system.service.sms.impl;
|
||||
|
||||
import cn.hutool.core.map.MapUtil;
|
||||
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.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.mysql.sms.SysSmsCodeMapper;
|
||||
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.service.sms.SysSmsCodeService;
|
||||
import org.springframework.data.redis.core.StringRedisTemplate;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.util.Date;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
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.util.servlet.ServletUtils.getClientIP;
|
||||
import static cn.iocoder.yudao.userserver.modules.system.enums.SysErrorCodeConstants.*;
|
||||
|
||||
/**
|
||||
|
@ -26,15 +33,26 @@ import static cn.iocoder.yudao.userserver.modules.system.enums.SysErrorCodeConst
|
|||
@Validated
|
||||
public class SysSmsCodeServiceImpl implements SysSmsCodeService {
|
||||
|
||||
/**
|
||||
* 验证码 + 手机 在redis中存储的有效时间,单位:分钟
|
||||
*/
|
||||
private static final Long CODE_TIME = 10L;
|
||||
|
||||
@Resource
|
||||
private SmsCodeProperties smsCodeProperties;
|
||||
|
||||
@Resource
|
||||
private SysSmsCodeMapper smsCodeMapper;
|
||||
|
||||
@Resource
|
||||
private MbrUserService mbrUserService;
|
||||
|
||||
@Resource
|
||||
private SysSmsCoreService smsCoreService;
|
||||
|
||||
@Resource
|
||||
private StringRedisTemplate stringRedisTemplate;
|
||||
|
||||
@Override
|
||||
public void sendSmsCode(String mobile, Integer scene, String createIp) {
|
||||
// 创建验证码
|
||||
|
@ -42,6 +60,21 @@ public class SysSmsCodeServiceImpl implements SysSmsCodeService {
|
|||
// 发送验证码
|
||||
smsCoreService.sendSingleSmsToMember(mobile, null, SysSmsTemplateCodeConstants.USER_SMS_LOGIN,
|
||||
MapUtil.of("code", code));
|
||||
|
||||
// 存储手机号与验证码到redis,用于标记
|
||||
stringRedisTemplate.opsForValue().set(code,mobile,CODE_TIME, TimeUnit.MINUTES);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendSmsNewCode(SysAuthSendSmsReqVO reqVO) {
|
||||
// 检测手机号是否已被使用
|
||||
MbrUserDO userByMobile = mbrUserService.getUserByMobile(reqVO.getMobile());
|
||||
if (userByMobile != null){
|
||||
throw exception(USER_SMS_CODE_IS_EXISTS);
|
||||
}
|
||||
|
||||
// 发送短信
|
||||
this.sendSmsCode(reqVO.getMobile(),reqVO.getScene(),getClientIP());
|
||||
}
|
||||
|
||||
private String createSmsCode(String mobile, Integer scene, String ip) {
|
||||
|
@ -91,4 +124,14 @@ public class SysSmsCodeServiceImpl implements SysSmsCodeService {
|
|||
.used(true).usedTime(new Date()).usedIp(usedIp).build());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendSmsCodeLogin(Long userId) {
|
||||
MbrUserDO user = mbrUserService.getUser(userId);
|
||||
if (user == null){
|
||||
throw exception(USER_NOT_EXISTS);
|
||||
}
|
||||
// 发送验证码
|
||||
this.sendSmsCode(user.getMobile(),SysSmsSceneEnum.CHANGE_MOBILE_BY_SMS.getScene(), getClientIP());
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,48 @@
|
|||
package cn.iocoder.yudao.userserver;
|
||||
|
||||
import cn.iocoder.yudao.framework.datasource.config.YudaoDataSourceAutoConfiguration;
|
||||
import cn.iocoder.yudao.framework.mybatis.config.YudaoMybatisAutoConfiguration;
|
||||
import cn.iocoder.yudao.framework.redis.config.YudaoRedisAutoConfiguration;
|
||||
import cn.iocoder.yudao.userserver.config.RedisTestConfiguration;
|
||||
import com.alibaba.druid.spring.boot.autoconfigure.DruidDataSourceAutoConfigure;
|
||||
import com.baomidou.mybatisplus.autoconfigure.MybatisPlusAutoConfiguration;
|
||||
import org.redisson.spring.starter.RedissonAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.jdbc.DataSourceTransactionManagerAutoConfiguration;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.context.annotation.Import;
|
||||
import org.springframework.test.context.ActiveProfiles;
|
||||
import org.springframework.test.context.jdbc.Sql;
|
||||
|
||||
/**
|
||||
* 依赖内存 DB + Redis 的单元测试
|
||||
*
|
||||
* 相比 {@link BaseDbUnitTest} 来说,额外增加了内存 Redis
|
||||
*
|
||||
* @author 芋道源码
|
||||
*/
|
||||
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.NONE, classes = BaseDbAndRedisUnitTest.Application.class)
|
||||
@ActiveProfiles("unit-test") // 设置使用 application-unit-test 配置文件
|
||||
@Sql(scripts = "/sql/clean.sql", executionPhase = Sql.ExecutionPhase.AFTER_TEST_METHOD) // 每个单元测试结束后,清理 DB
|
||||
public class BaseDbAndRedisUnitTest {
|
||||
|
||||
@Import({
|
||||
// DB 配置类
|
||||
YudaoDataSourceAutoConfiguration.class, // 自己的 DB 配置类
|
||||
DataSourceAutoConfiguration.class, // Spring DB 自动配置类
|
||||
DataSourceTransactionManagerAutoConfiguration.class, // Spring 事务自动配置类
|
||||
DruidDataSourceAutoConfigure.class, // Druid 自动配置类
|
||||
// MyBatis 配置类
|
||||
YudaoMybatisAutoConfiguration.class, // 自己的 MyBatis 配置类
|
||||
MybatisPlusAutoConfiguration.class, // MyBatis 的自动配置类
|
||||
// Redis 配置类
|
||||
RedisTestConfiguration.class, // Redis 测试配置类,用于启动 RedisServer
|
||||
RedisAutoConfiguration.class, // Spring Redis 自动配置类
|
||||
YudaoRedisAutoConfiguration.class, // 自己的 Redis 配置类
|
||||
RedissonAutoConfiguration.class, // Redisson 自动高配置类
|
||||
})
|
||||
public static class Application {
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,30 @@
|
|||
package cn.iocoder.yudao.userserver.config;
|
||||
|
||||
import com.github.fppt.jedismock.RedisServer;
|
||||
import org.springframework.boot.autoconfigure.data.redis.RedisProperties;
|
||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Lazy;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@Lazy(false) // 禁止延迟加载
|
||||
@EnableConfigurationProperties(RedisProperties.class)
|
||||
public class RedisTestConfiguration {
|
||||
|
||||
/**
|
||||
* 创建模拟的 Redis Server 服务器
|
||||
*/
|
||||
@Bean
|
||||
public RedisServer redisServer(RedisProperties properties) throws IOException {
|
||||
RedisServer redisServer = new RedisServer(properties.getPort());
|
||||
// TODO 芋艿:一次执行多个单元测试时,貌似创建多个 spring 容器,导致不进行 stop。这样,就导致端口被占用,无法启动。。。
|
||||
try {
|
||||
redisServer.start();
|
||||
} catch (Exception ignore) {}
|
||||
return redisServer;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,59 @@
|
|||
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.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 宋天
|
||||
*/
|
||||
public class SysUserProfileControllerTest {
|
||||
|
||||
private MockMvc mockMvc;
|
||||
|
||||
@InjectMocks
|
||||
private SysUserProfileController sysUserProfileController;
|
||||
|
||||
@Mock
|
||||
private MbrUserService userService;
|
||||
|
||||
@Mock
|
||||
private SysSmsCodeService smsCodeService;
|
||||
|
||||
@Before
|
||||
public void setup() {
|
||||
// 初始化
|
||||
MockitoAnnotations.openMocks(this);
|
||||
|
||||
// 构建mvc环境
|
||||
mockMvc = MockMvcBuilders.standaloneSetup(sysUserProfileController).build();
|
||||
}
|
||||
|
||||
@Test
|
||||
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());
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -2,28 +2,32 @@ package cn.iocoder.yudao.userserver.modules.member.service;
|
|||
|
||||
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.system.dal.dataobject.user.SysUserDO;
|
||||
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
|
||||
import cn.iocoder.yudao.framework.common.util.collection.ArrayUtils;
|
||||
import cn.iocoder.yudao.framework.redis.config.YudaoRedisAutoConfiguration;
|
||||
import cn.iocoder.yudao.userserver.BaseDbAndRedisUnitTest;
|
||||
import cn.iocoder.yudao.userserver.BaseDbUnitTest;
|
||||
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.dal.mysql.user.MbrUserMapper;
|
||||
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.enums.sms.SysSmsSceneEnum;
|
||||
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.impl.SysSmsCodeServiceImpl;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.boot.test.mock.mockito.MockBean;
|
||||
import org.springframework.context.annotation.Import;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.mock.web.MockMultipartFile;
|
||||
import org.springframework.data.redis.core.StringRedisTemplate;
|
||||
import org.springframework.security.crypto.password.PasswordEncoder;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.io.*;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import static cn.hutool.core.util.RandomUtil.randomBytes;
|
||||
import static cn.hutool.core.util.RandomUtil.*;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static cn.hutool.core.util.RandomUtil.randomEle;
|
||||
import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomPojo;
|
||||
import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomString;
|
||||
import static org.mockito.Mockito.*;
|
||||
|
@ -32,21 +36,30 @@ import static org.mockito.Mockito.*;
|
|||
*
|
||||
* @author 宋天
|
||||
*/
|
||||
@Import(MbrUserServiceImpl.class)
|
||||
public class MbrUserServiceImplTest extends BaseDbUnitTest {
|
||||
@Import({MbrUserServiceImpl.class, YudaoRedisAutoConfiguration.class})
|
||||
public class MbrUserServiceImplTest extends BaseDbAndRedisUnitTest {
|
||||
|
||||
@Resource
|
||||
private MbrUserServiceImpl mbrUserService;
|
||||
|
||||
@Resource
|
||||
private StringRedisTemplate stringRedisTemplate;
|
||||
|
||||
@Resource
|
||||
private MbrUserMapper userMapper;
|
||||
|
||||
@MockBean
|
||||
private SysAuthServiceImpl authService;
|
||||
|
||||
@MockBean
|
||||
private InfFileCoreService fileCoreService;
|
||||
|
||||
@MockBean
|
||||
private PasswordEncoder passwordEncoder;
|
||||
|
||||
@MockBean
|
||||
private SysSmsCodeService sysSmsCodeService;
|
||||
|
||||
@Test
|
||||
public void testUpdateNickName_success(){
|
||||
// mock 数据
|
||||
|
@ -94,6 +107,37 @@ public class MbrUserServiceImplTest extends BaseDbUnitTest {
|
|||
assertEquals(avatar, str);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void updateMobile_success(){
|
||||
// mock数据
|
||||
String oldMobile = randomNumbers(11);
|
||||
MbrUserDO userDO = randomMbrUserDO();
|
||||
userDO.setMobile(oldMobile);
|
||||
userMapper.insert(userDO);
|
||||
|
||||
// 验证旧手机
|
||||
sysSmsCodeService.sendSmsCodeLogin(userDO.getId());
|
||||
|
||||
// 验证旧手机验证码是否正确
|
||||
sysSmsCodeService.useSmsCode(oldMobile,SysSmsSceneEnum.CHANGE_MOBILE_BY_SMS.getScene(),"123","1.1.1.1");
|
||||
|
||||
// 验证新手机
|
||||
SysAuthSendSmsReqVO smsReqVO = new SysAuthSendSmsReqVO();
|
||||
smsReqVO.setMobile(oldMobile);
|
||||
smsReqVO.setScene(SysSmsSceneEnum.CHANGE_MOBILE_BY_SMS.getScene());
|
||||
sysSmsCodeService.sendSmsNewCode(smsReqVO);
|
||||
|
||||
// 更新手机号
|
||||
String newMobile = randomNumbers(11);
|
||||
String code = randomNumbers(4);
|
||||
MbrUserUpdateMobileReqVO reqVO = new MbrUserUpdateMobileReqVO();
|
||||
reqVO.setMobile(newMobile);
|
||||
reqVO.setCode(code);
|
||||
mbrUserService.updateMobile(userDO.getId(),reqVO);
|
||||
|
||||
assertEquals(mbrUserService.getUser(userDO.getId()).getMobile(),newMobile);
|
||||
}
|
||||
|
||||
// ========== 随机对象 ==========
|
||||
|
||||
@SafeVarargs
|
||||
|
|
|
@ -0,0 +1,75 @@
|
|||
package cn.iocoder.yudao.userserver.modules.system.controller;
|
||||
|
||||
import cn.iocoder.yudao.coreservice.modules.system.service.social.SysSocialService;
|
||||
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.http.HttpHeaders.AUTHORIZATION;
|
||||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
|
||||
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 SysSocialService 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());
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
|
@ -0,0 +1,134 @@
|
|||
package cn.iocoder.yudao.userserver.modules.system.service;
|
||||
|
||||
import cn.hutool.core.util.ArrayUtil;
|
||||
import cn.iocoder.yudao.coreservice.modules.member.dal.dataobject.user.MbrUserDO;
|
||||
import cn.iocoder.yudao.coreservice.modules.system.dal.dataobject.user.SysUserDO;
|
||||
import cn.iocoder.yudao.coreservice.modules.system.service.auth.SysUserSessionCoreService;
|
||||
import cn.iocoder.yudao.coreservice.modules.system.service.logger.SysLoginLogCoreService;
|
||||
import cn.iocoder.yudao.coreservice.modules.system.service.social.SysSocialService;
|
||||
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
|
||||
import cn.iocoder.yudao.framework.common.util.collection.ArrayUtils;
|
||||
import cn.iocoder.yudao.framework.redis.config.YudaoRedisAutoConfiguration;
|
||||
import cn.iocoder.yudao.userserver.BaseDbAndRedisUnitTest;
|
||||
import cn.iocoder.yudao.userserver.BaseDbUnitTest;
|
||||
import cn.iocoder.yudao.userserver.config.RedisTestConfiguration;
|
||||
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.impl.MbrUserServiceImpl;
|
||||
import cn.iocoder.yudao.userserver.modules.system.controller.auth.vo.MbrAuthResetPasswordReqVO;
|
||||
import cn.iocoder.yudao.userserver.modules.system.service.auth.SysAuthService;
|
||||
import cn.iocoder.yudao.userserver.modules.system.service.auth.impl.SysAuthServiceImpl;
|
||||
import cn.iocoder.yudao.userserver.modules.system.service.sms.SysSmsCodeService;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.boot.test.mock.mockito.MockBean;
|
||||
import org.springframework.context.annotation.Import;
|
||||
import org.springframework.data.redis.core.StringRedisTemplate;
|
||||
import org.springframework.security.authentication.AuthenticationManager;
|
||||
import org.springframework.security.crypto.password.PasswordEncoder;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import static cn.hutool.core.util.RandomUtil.randomEle;
|
||||
import static cn.hutool.core.util.RandomUtil.randomNumbers;
|
||||
import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.*;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.mockito.Mockito.*;
|
||||
|
||||
|
||||
/**
|
||||
* {@link SysAuthService} 的单元测试类
|
||||
*
|
||||
* @author 宋天
|
||||
*/
|
||||
@Import({SysAuthServiceImpl.class, YudaoRedisAutoConfiguration.class})
|
||||
public class SysAuthServiceTest extends BaseDbAndRedisUnitTest {
|
||||
|
||||
@MockBean
|
||||
private AuthenticationManager authenticationManager;
|
||||
@MockBean
|
||||
private MbrUserService userService;
|
||||
@MockBean
|
||||
private SysSmsCodeService smsCodeService;
|
||||
@MockBean
|
||||
private SysLoginLogCoreService loginLogCoreService;
|
||||
@MockBean
|
||||
private SysUserSessionCoreService userSessionCoreService;
|
||||
@MockBean
|
||||
private SysSocialService socialService;
|
||||
@Resource
|
||||
private StringRedisTemplate stringRedisTemplate;
|
||||
@MockBean
|
||||
private PasswordEncoder passwordEncoder;
|
||||
@Resource
|
||||
private MbrUserMapper mbrUserMapper;
|
||||
@Resource
|
||||
private SysAuthServiceImpl authService;
|
||||
|
||||
|
||||
@Test
|
||||
public void testUpdatePassword_success(){
|
||||
// 准备参数
|
||||
MbrUserDO userDO = randomMbrUserDO();
|
||||
mbrUserMapper.insert(userDO);
|
||||
|
||||
// 新密码
|
||||
String newPassword = randomString();
|
||||
|
||||
// 请求实体
|
||||
MbrAuthResetPasswordReqVO reqVO = new MbrAuthResetPasswordReqVO();
|
||||
reqVO.setOldPassword(userDO.getPassword());
|
||||
reqVO.setPassword(newPassword);
|
||||
|
||||
// 测试桩
|
||||
// 这两个相等是为了返回ture这个结果
|
||||
when(passwordEncoder.matches(reqVO.getOldPassword(),reqVO.getOldPassword())).thenReturn(true);
|
||||
when(passwordEncoder.encode(newPassword)).thenReturn(newPassword);
|
||||
|
||||
// 更新用户密码
|
||||
authService.updatePassword(userDO.getId(),reqVO);
|
||||
assertEquals(mbrUserMapper.selectById(userDO.getId()).getPassword(),newPassword);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testResetPassword_success(){
|
||||
// 准备参数
|
||||
MbrUserDO userDO = randomMbrUserDO();
|
||||
mbrUserMapper.insert(userDO);
|
||||
|
||||
// 随机密码
|
||||
String password = randomNumbers(11);
|
||||
// 随机验证码
|
||||
String code = randomNumbers(4);
|
||||
|
||||
MbrAuthResetPasswordReqVO reqVO = new MbrAuthResetPasswordReqVO();
|
||||
reqVO.setPassword(password);
|
||||
reqVO.setCode(code);
|
||||
|
||||
// 放入code+手机号
|
||||
stringRedisTemplate.opsForValue().set(code,userDO.getMobile(),10, TimeUnit.MINUTES);
|
||||
|
||||
// mock
|
||||
when(passwordEncoder.encode(password)).thenReturn(password);
|
||||
|
||||
// 更新用户密码
|
||||
authService.resetPassword(reqVO);
|
||||
assertEquals(mbrUserMapper.selectById(userDO.getId()).getPassword(),password);
|
||||
}
|
||||
|
||||
|
||||
// ========== 随机对象 ==========
|
||||
|
||||
@SafeVarargs
|
||||
private static MbrUserDO randomMbrUserDO(Consumer<MbrUserDO>... consumers) {
|
||||
Consumer<MbrUserDO> consumer = (o) -> {
|
||||
o.setStatus(randomEle(CommonStatusEnum.values()).getStatus()); // 保证 status 的范围
|
||||
o.setPassword(randomString());
|
||||
};
|
||||
return randomPojo(MbrUserDO.class, ArrayUtils.append(consumer, consumers));
|
||||
}
|
||||
|
||||
|
||||
}
|
Loading…
Reference in New Issue