多模块重构 4:system 模块的调整,实现 sms API~~

This commit is contained in:
YunaiV 2022-01-30 22:27:54 +08:00
parent add08b1ecd
commit 16c2590483
14 changed files with 270 additions and 83 deletions

View File

@ -14,9 +14,8 @@
<module>yudao-user-server</module> <module>yudao-user-server</module>
<module>yudao-core-service</module> <module>yudao-core-service</module>
<module>yudao-module-member</module> <module>yudao-module-member</module>
<module>yudao-module-bpm</module> <!-- <module>yudao-module-bpm</module>-->
<module>yudao-module-system</module> <module>yudao-module-system</module>
<module>yudao-module-system-api</module>
</modules> </modules>
<name>${artifactId}</name> <name>${artifactId}</name>

View File

@ -57,14 +57,15 @@
</dependency> </dependency>
<!-- 默认引入bpm-activiti. 可以替换为bpm-flowable --> <!-- 默认引入bpm-activiti. 可以替换为bpm-flowable -->
<dependency> <!-- TODO 芋艿:临时注释,测试通过后,打开 -->
<groupId>cn.iocoder.boot</groupId> <!-- <dependency>-->
<artifactId>yudao-module-bpm-activiti</artifactId> <!-- <groupId>cn.iocoder.boot</groupId>-->
</dependency> <!-- <artifactId>yudao-module-bpm-activiti</artifactId>-->
<dependency> <!-- </dependency>-->
<groupId>cn.iocoder.boot</groupId> <!-- <dependency>-->
<artifactId>yudao-module-bpm-core-service-impl</artifactId> <!-- <groupId>cn.iocoder.boot</groupId>-->
</dependency> <!-- <artifactId>yudao-module-bpm-core-service-impl</artifactId>-->
<!-- </dependency>-->
<!-- Web 相关 --> <!-- Web 相关 -->
<dependency> <dependency>
<groupId>cn.iocoder.boot</groupId> <groupId>cn.iocoder.boot</groupId>

View File

@ -2,13 +2,13 @@ package cn.iocoder.yudao.module.member.convert.auth;
import cn.iocoder.yudao.framework.common.enums.UserTypeEnum; import cn.iocoder.yudao.framework.common.enums.UserTypeEnum;
import cn.iocoder.yudao.framework.security.core.LoginUser; import cn.iocoder.yudao.framework.security.core.LoginUser;
import cn.iocoder.yudao.module.member.controller.app.auth.vo.AppAuthSocialBindReqVO; import cn.iocoder.yudao.module.member.controller.app.auth.vo.*;
import cn.iocoder.yudao.module.member.controller.app.auth.vo.AppAuthSocialLogin2ReqVO;
import cn.iocoder.yudao.module.member.controller.app.auth.vo.AppAuthSocialLoginReqVO;
import cn.iocoder.yudao.module.member.controller.app.auth.vo.AppAuthSocialUnbindReqVO;
import cn.iocoder.yudao.module.member.dal.dataobject.user.MemberUserDO; import cn.iocoder.yudao.module.member.dal.dataobject.user.MemberUserDO;
import cn.iocoder.yudao.module.system.api.sms.dto.SmsCodeSendReqDTO;
import cn.iocoder.yudao.module.system.api.sms.dto.SmsCodeUseReqDTO;
import cn.iocoder.yudao.module.system.api.social.dto.SocialUserBindReqDTO; import cn.iocoder.yudao.module.system.api.social.dto.SocialUserBindReqDTO;
import cn.iocoder.yudao.module.system.api.social.dto.SocialUserUnbindReqDTO; import cn.iocoder.yudao.module.system.api.social.dto.SocialUserUnbindReqDTO;
import cn.iocoder.yudao.module.system.enums.sms.SmsSceneEnum;
import org.mapstruct.Mapper; import org.mapstruct.Mapper;
import org.mapstruct.Mapping; import org.mapstruct.Mapping;
import org.mapstruct.factory.Mappers; import org.mapstruct.factory.Mappers;
@ -31,4 +31,8 @@ public interface AuthConvert {
SocialUserBindReqDTO convert(Long userId, Integer value, AppAuthSocialLoginReqVO reqVO); SocialUserBindReqDTO convert(Long userId, Integer value, AppAuthSocialLoginReqVO reqVO);
SocialUserUnbindReqDTO convert(Long userId, Integer value, AppAuthSocialUnbindReqVO reqVO); SocialUserUnbindReqDTO convert(Long userId, Integer value, AppAuthSocialUnbindReqVO reqVO);
SmsCodeSendReqDTO convert(AppAuthSendSmsReqVO reqVO);
SmsCodeUseReqDTO convert(AppAuthResetPasswordReqVO reqVO, SmsSceneEnum scene, String usedIp);
SmsCodeUseReqDTO convert(AppAuthSmsLoginReqVO reqVO, Integer scene, String userIp);
} }

View File

@ -15,6 +15,7 @@ import cn.iocoder.yudao.module.member.service.user.MemberUserService;
import cn.iocoder.yudao.module.system.api.auth.UserSessionApi; import cn.iocoder.yudao.module.system.api.auth.UserSessionApi;
import cn.iocoder.yudao.module.system.api.logger.LoginLogApi; import cn.iocoder.yudao.module.system.api.logger.LoginLogApi;
import cn.iocoder.yudao.module.system.api.logger.dto.LoginLogCreateReqDTO; import cn.iocoder.yudao.module.system.api.logger.dto.LoginLogCreateReqDTO;
import cn.iocoder.yudao.module.system.api.sms.SmsCodeApi;
import cn.iocoder.yudao.module.system.api.social.SocialUserApi; import cn.iocoder.yudao.module.system.api.social.SocialUserApi;
import cn.iocoder.yudao.module.system.enums.logger.LoginLogTypeEnum; import cn.iocoder.yudao.module.system.enums.logger.LoginLogTypeEnum;
import cn.iocoder.yudao.module.system.enums.logger.LoginResultEnum; import cn.iocoder.yudao.module.system.enums.logger.LoginResultEnum;
@ -56,7 +57,7 @@ public class MemberAuthServiceImpl implements MemberAuthService {
@Resource @Resource
private MemberUserService userService; private MemberUserService userService;
@Resource @Resource
private SysSmsCodeService smsCodeService; private SmsCodeApi smsCodeApi;
@Resource @Resource
private LoginLogApi loginLogApi; private LoginLogApi loginLogApi;
@Resource @Resource
@ -93,8 +94,7 @@ public class MemberAuthServiceImpl implements MemberAuthService {
@Transactional @Transactional
public String smsLogin(AppAuthSmsLoginReqVO reqVO, String userIp, String userAgent) { public String smsLogin(AppAuthSmsLoginReqVO reqVO, String userIp, String userAgent) {
// 校验验证码 // 校验验证码
smsCodeService.useSmsCode(reqVO.getMobile(), SmsSceneEnum.MEMBER_LOGIN.getScene(), smsCodeApi.useSmsCode(AuthConvert.INSTANCE.convert(reqVO, SmsSceneEnum.MEMBER_LOGIN.getScene(), userIp));
reqVO.getCode(), userIp);
// 获得获得注册用户 // 获得获得注册用户
MemberUserDO user = userService.createUserIfAbsent(reqVO.getMobile(), userIp); MemberUserDO user = userService.createUserIfAbsent(reqVO.getMobile(), userIp);
@ -292,8 +292,8 @@ public class MemberAuthServiceImpl implements MemberAuthService {
MemberUserDO userDO = checkUserIfExists(reqVO.getMobile()); MemberUserDO userDO = checkUserIfExists(reqVO.getMobile());
// 使用验证码 // 使用验证码
smsCodeService.useSmsCode(reqVO.getMobile(), SmsSceneEnum.MEMBER_FORGET_PASSWORD.getScene(), reqVO.getCode(), smsCodeApi.useSmsCode(AuthConvert.INSTANCE.convert(reqVO, SmsSceneEnum.MEMBER_FORGET_PASSWORD,
getClientIP()); getClientIP()));
// 更新密码 // 更新密码
MemberUserDO mbrUserDO = MemberUserDO.builder().build(); MemberUserDO mbrUserDO = MemberUserDO.builder().build();
@ -304,7 +304,8 @@ public class MemberAuthServiceImpl implements MemberAuthService {
@Override @Override
public void sendSmsCode(Long userId, AppAuthSendSmsReqVO reqVO) { public void sendSmsCode(Long userId, AppAuthSendSmsReqVO reqVO) {
// TODO 芋艿修改 // TODO 要根据不同的场景校验是否有用户
smsCodeApi.sendSmsCode(AuthConvert.INSTANCE.convert(reqVO));
} }
/** /**

View File

@ -4,14 +4,12 @@ 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.framework.common.enums.CommonStatusEnum; import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
import cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil;
import cn.iocoder.yudao.module.member.controller.app.user.vo.AppUserUpdateMobileReqVO; import cn.iocoder.yudao.module.member.controller.app.user.vo.AppUserUpdateMobileReqVO;
import cn.iocoder.yudao.module.member.dal.dataobject.sms.SmsCodeDO;
import cn.iocoder.yudao.module.member.dal.dataobject.user.MemberUserDO; import cn.iocoder.yudao.module.member.dal.dataobject.user.MemberUserDO;
import cn.iocoder.yudao.module.member.dal.mysql.user.MemberUserMapper; import cn.iocoder.yudao.module.member.dal.mysql.user.MemberUserMapper;
import cn.iocoder.yudao.module.member.enums.SysErrorCodeConstants; import cn.iocoder.yudao.module.system.api.sms.SmsCodeApi;
import cn.iocoder.yudao.module.system.api.sms.dto.SmsCodeUseReqDTO;
import cn.iocoder.yudao.module.system.enums.sms.SmsSceneEnum; import cn.iocoder.yudao.module.system.enums.sms.SmsSceneEnum;
import cn.iocoder.yudao.module.member.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;
@ -43,7 +41,7 @@ public class MemberUserServiceImpl implements MemberUserService {
@Resource @Resource
private InfFileCoreService fileCoreService; private InfFileCoreService fileCoreService;
@Resource @Resource
private SysSmsCodeService smsCodeService; private SmsCodeApi smsCodeApi;
@Resource @Resource
private PasswordEncoder passwordEncoder; private PasswordEncoder passwordEncoder;
@ -111,22 +109,19 @@ public class MemberUserServiceImpl implements MemberUserService {
return avatar; return avatar;
} }
@Override
@Transactional(rollbackFor = Exception.class) @Transactional(rollbackFor = Exception.class)
public void updateUserMobile(Long userId, AppUserUpdateMobileReqVO reqVO) { public void updateUserMobile(Long userId, AppUserUpdateMobileReqVO reqVO) {
// 检测用户是否存在 // 检测用户是否存在
checkUserExists(userId); checkUserExists(userId);
// TODO 芋艿oldMobile 应该不用传递
// 校验旧手机和旧验证码 // 校验旧手机和旧验证码
SmsCodeDO sysSmsCodeDO = smsCodeService.checkCodeIsExpired(reqVO.getOldMobile(), reqVO.getOldCode(), smsCodeApi.useSmsCode(new SmsCodeUseReqDTO().setMobile(reqVO.getOldMobile()).setCode(reqVO.getOldCode())
SmsSceneEnum.MEMBER_UPDATE_MOBILE.getScene()); .setScene(SmsSceneEnum.MEMBER_UPDATE_MOBILE.getScene()).setUsedIp(getClientIP()));
// 判断旧 code 是否未被使用如果是抛出异常
if (Boolean.FALSE.equals(sysSmsCodeDO.getUsed())){
throw ServiceExceptionUtil.exception(SysErrorCodeConstants.USER_SMS_CODE_IS_UNUSED);
}
// 使用新验证码 // 使用新验证码
smsCodeService.useSmsCode(reqVO.getMobile(), SmsSceneEnum.MEMBER_UPDATE_MOBILE.getScene(), smsCodeApi.useSmsCode(new SmsCodeUseReqDTO().setMobile(reqVO.getMobile()).setCode(reqVO.getCode())
reqVO.getCode(),getClientIP()); .setScene(SmsSceneEnum.MEMBER_UPDATE_MOBILE.getScene()).setUsedIp(getClientIP()));
// 更新用户手机 // 更新用户手机
memberUserMapper.updateById(MemberUserDO.builder().id(userId).mobile(reqVO.getMobile()).build()); memberUserMapper.updateById(MemberUserDO.builder().id(userId).mobile(reqVO.getMobile()).build());

View File

@ -1,22 +1,21 @@
package cn.iocoder.yudao.module.member.service.auth; package cn.iocoder.yudao.module.member.service.auth;
import cn.iocoder.yudao.module.member.dal.dataobject.user.MemberUserDO;
import cn.iocoder.yudao.module.system.service.auth.SysUserSessionCoreService;
import cn.iocoder.yudao.module.system.service.logger.SysLoginLogCoreService;
import cn.iocoder.yudao.module.system.service.social.SysSocialCoreService;
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
import cn.iocoder.yudao.framework.common.util.collection.ArrayUtils; import cn.iocoder.yudao.framework.common.util.collection.ArrayUtils;
import cn.iocoder.yudao.framework.redis.config.YudaoRedisAutoConfiguration; import cn.iocoder.yudao.framework.redis.config.YudaoRedisAutoConfiguration;
import cn.iocoder.yudao.module.member.controller.app.auth.vo.AppAuthResetPasswordReqVO; import cn.iocoder.yudao.module.member.controller.app.auth.vo.AppAuthResetPasswordReqVO;
import cn.iocoder.yudao.module.member.controller.app.auth.vo.AppAuthUpdatePasswordReqVO; import cn.iocoder.yudao.module.member.controller.app.auth.vo.AppAuthUpdatePasswordReqVO;
import cn.iocoder.yudao.module.member.dal.dataobject.user.MemberUserDO;
import cn.iocoder.yudao.module.member.dal.mysql.user.MemberUserMapper; import cn.iocoder.yudao.module.member.dal.mysql.user.MemberUserMapper;
import cn.iocoder.yudao.module.member.service.sms.SysSmsCodeService;
import cn.iocoder.yudao.module.member.service.user.MemberUserService; import cn.iocoder.yudao.module.member.service.user.MemberUserService;
import cn.iocoder.yudao.module.member.test.BaseDbAndRedisUnitTest; import cn.iocoder.yudao.module.member.test.BaseDbAndRedisUnitTest;
import cn.iocoder.yudao.module.system.api.auth.UserSessionApi;
import cn.iocoder.yudao.module.system.api.logger.LoginLogApi;
import cn.iocoder.yudao.module.system.api.sms.SmsCodeApi;
import cn.iocoder.yudao.module.system.api.social.SocialUserApi;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import org.springframework.boot.test.mock.mockito.MockBean; import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.context.annotation.Import; import org.springframework.context.annotation.Import;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.security.authentication.AuthenticationManager; import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.security.crypto.password.PasswordEncoder;
@ -37,22 +36,20 @@ import static org.mockito.Mockito.when;
* @author 宋天 * @author 宋天
*/ */
@Import({MemberAuthServiceImpl.class, YudaoRedisAutoConfiguration.class}) @Import({MemberAuthServiceImpl.class, YudaoRedisAutoConfiguration.class})
public class SysAuthServiceTest extends BaseDbAndRedisUnitTest { public class MemberAuthServiceTest extends BaseDbAndRedisUnitTest {
@MockBean @MockBean
private AuthenticationManager authenticationManager; private AuthenticationManager authenticationManager;
@MockBean @MockBean
private MemberUserService userService; private MemberUserService userService;
@MockBean @MockBean
private SysSmsCodeService smsCodeService; private SmsCodeApi smsCodeApi;
@MockBean @MockBean
private SysLoginLogCoreService loginLogCoreService; private LoginLogApi loginLogApi;
@MockBean @MockBean
private SysUserSessionCoreService userSessionCoreService; private UserSessionApi userSessionApi;
@MockBean @MockBean
private SysSocialCoreService socialService; private SocialUserApi socialUserApi;
@Resource
private StringRedisTemplate stringRedisTemplate;
@MockBean @MockBean
private PasswordEncoder passwordEncoder; private PasswordEncoder passwordEncoder;
@Resource @Resource

View File

@ -6,13 +6,11 @@ import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
import cn.iocoder.yudao.framework.common.util.collection.ArrayUtils; import cn.iocoder.yudao.framework.common.util.collection.ArrayUtils;
import cn.iocoder.yudao.framework.redis.config.YudaoRedisAutoConfiguration; import cn.iocoder.yudao.framework.redis.config.YudaoRedisAutoConfiguration;
import cn.iocoder.yudao.module.member.controller.app.user.vo.AppUserUpdateMobileReqVO; import cn.iocoder.yudao.module.member.controller.app.user.vo.AppUserUpdateMobileReqVO;
import cn.iocoder.yudao.module.member.dal.dataobject.sms.SmsCodeDO;
import cn.iocoder.yudao.module.member.dal.dataobject.user.MemberUserDO; import cn.iocoder.yudao.module.member.dal.dataobject.user.MemberUserDO;
import cn.iocoder.yudao.module.member.dal.mysql.user.MemberUserMapper; import cn.iocoder.yudao.module.member.dal.mysql.user.MemberUserMapper;
import cn.iocoder.yudao.module.system.enums.sms.SmsSceneEnum;
import cn.iocoder.yudao.module.member.service.auth.MemberAuthServiceImpl; import cn.iocoder.yudao.module.member.service.auth.MemberAuthServiceImpl;
import cn.iocoder.yudao.module.member.service.sms.SysSmsCodeService;
import cn.iocoder.yudao.module.member.test.BaseDbAndRedisUnitTest; import cn.iocoder.yudao.module.member.test.BaseDbAndRedisUnitTest;
import cn.iocoder.yudao.module.system.api.sms.SmsCodeApi;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import org.springframework.boot.test.mock.mockito.MockBean; import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.context.annotation.Import; import org.springframework.context.annotation.Import;
@ -36,7 +34,7 @@ import static org.mockito.Mockito.*;
* @author 宋天 * @author 宋天
*/ */
@Import({MemberUserServiceImpl.class, YudaoRedisAutoConfiguration.class}) @Import({MemberUserServiceImpl.class, YudaoRedisAutoConfiguration.class})
public class UserServiceImplTest extends BaseDbAndRedisUnitTest { public class MemberUserServiceImplTest extends BaseDbAndRedisUnitTest {
@Resource @Resource
private MemberUserServiceImpl mbrUserService; private MemberUserServiceImpl mbrUserService;
@ -57,7 +55,7 @@ public class UserServiceImplTest extends BaseDbAndRedisUnitTest {
private PasswordEncoder passwordEncoder; private PasswordEncoder passwordEncoder;
@MockBean @MockBean
private SmsCodeService smsCodeService; private SmsCodeApi smsCodeApi;
@Test @Test
public void testUpdateNickName_success(){ public void testUpdateNickName_success(){
@ -103,14 +101,15 @@ public class UserServiceImplTest extends BaseDbAndRedisUnitTest {
userDO.setMobile(oldMobile); userDO.setMobile(oldMobile);
userMapper.insert(userDO); userMapper.insert(userDO);
// TODO 芋艿需要修复该单元测试重构多模块带来的
// 旧手机和旧验证码 // 旧手机和旧验证码
SmsCodeDO codeDO = new SmsCodeDO(); // SmsCodeDO codeDO = new SmsCodeDO();
String oldCode = RandomUtil.randomString(4); String oldCode = RandomUtil.randomString(4);
codeDO.setMobile(userDO.getMobile()); // codeDO.setMobile(userDO.getMobile());
codeDO.setCode(oldCode); // codeDO.setCode(oldCode);
codeDO.setScene(SmsSceneEnum.MEMBER_UPDATE_MOBILE.getScene()); // codeDO.setScene(SmsSceneEnum.MEMBER_UPDATE_MOBILE.getScene());
codeDO.setUsed(Boolean.FALSE); // codeDO.setUsed(Boolean.FALSE);
when(smsCodeService.checkCodeIsExpired(codeDO.getMobile(),codeDO.getCode(),codeDO.getScene())).thenReturn(codeDO); // when(smsCodeService.checkCodeIsExpired(codeDO.getMobile(),codeDO.getCode(),codeDO.getScene())).thenReturn(codeDO);
// 更新手机号 // 更新手机号
String newMobile = randomNumbers(11); String newMobile = randomNumbers(11);

View File

@ -0,0 +1,40 @@
package cn.iocoder.yudao.module.system.api.sms;
import cn.iocoder.yudao.framework.common.exception.ServiceException;
import cn.iocoder.yudao.module.system.api.sms.dto.SmsCodeCheckReqDTO;
import cn.iocoder.yudao.module.system.api.sms.dto.SmsCodeSendReqDTO;
import cn.iocoder.yudao.module.system.api.sms.dto.SmsCodeUseReqDTO;
import javax.validation.Valid;
/**
* 短信验证码 API 接口
*
* @author 芋道源码
*/
public interface SmsCodeApi {
/**
* 创建短信验证码并进行发送
*
* @param reqDTO 发送请求
*/
void sendSmsCode(@Valid SmsCodeSendReqDTO reqDTO);
/**
* 验证短信验证码并进行使用
* 如果正确则将验证码标记成已使用
* 如果错误则抛出 {@link ServiceException} 异常
*
* @param reqDTO 使用请求
*/
void useSmsCode(@Valid SmsCodeUseReqDTO reqDTO);
/**
* 检查验证码是否有效
*
* @param reqDTO 校验请求
*/
void checkSmsCode(@Valid SmsCodeCheckReqDTO reqDTO);
}

View File

@ -0,0 +1,36 @@
package cn.iocoder.yudao.module.system.api.sms.dto;
import cn.iocoder.yudao.framework.common.validation.InEnum;
import cn.iocoder.yudao.framework.common.validation.Mobile;
import cn.iocoder.yudao.module.system.enums.sms.SmsSceneEnum;
import lombok.Data;
import javax.validation.constraints.NotEmpty;
/**
* 短信验证码的校验 Request DTO
*
* @author 芋道源码
*/
@Data
public class SmsCodeCheckReqDTO {
/**
* 手机号
*/
@Mobile
@NotEmpty(message = "手机号不能为空")
private String mobile;
/**
* 发送场景
*/
@NotEmpty(message = "发送场景不能为空")
@InEnum(SmsSceneEnum.class)
private Integer scene;
/**
* 验证码
*/
@NotEmpty(message = "验证码")
private String code;
}

View File

@ -0,0 +1,36 @@
package cn.iocoder.yudao.module.system.api.sms.dto;
import cn.iocoder.yudao.framework.common.validation.InEnum;
import cn.iocoder.yudao.framework.common.validation.Mobile;
import cn.iocoder.yudao.module.system.enums.sms.SmsSceneEnum;
import lombok.Data;
import javax.validation.constraints.NotEmpty;
/**
* 短信验证码的发送 Request DTO
*
* @author 芋道源码
*/
@Data
public class SmsCodeSendReqDTO {
/**
* 手机号
*/
@Mobile
@NotEmpty(message = "手机号不能为空")
private String mobile;
/**
* 发送场景
*/
@NotEmpty(message = "发送场景不能为空")
@InEnum(SmsSceneEnum.class)
private Integer scene;
/**
* 发送 IP
*/
@NotEmpty(message = "发送 IP 不能为空")
private String createIp;
}

View File

@ -0,0 +1,41 @@
package cn.iocoder.yudao.module.system.api.sms.dto;
import cn.iocoder.yudao.framework.common.validation.InEnum;
import cn.iocoder.yudao.framework.common.validation.Mobile;
import cn.iocoder.yudao.module.system.enums.sms.SmsSceneEnum;
import lombok.Data;
import javax.validation.constraints.NotEmpty;
/**
* 短信验证码的使用 Request DTO
*
* @author 芋道源码
*/
@Data
public class SmsCodeUseReqDTO {
/**
* 手机号
*/
@Mobile
@NotEmpty(message = "手机号不能为空")
private String mobile;
/**
* 发送场景
*/
@NotEmpty(message = "发送场景不能为空")
@InEnum(SmsSceneEnum.class)
private Integer scene;
/**
* 验证码
*/
@NotEmpty(message = "验证码")
private String code;
/**
* 使用 IP
*/
@NotEmpty(message = "使用 IP 不能为空")
private String usedIp;
}

View File

@ -0,0 +1,39 @@
package cn.iocoder.yudao.module.system.api.sms;
import cn.iocoder.yudao.module.system.api.sms.dto.SmsCodeCheckReqDTO;
import cn.iocoder.yudao.module.system.api.sms.dto.SmsCodeSendReqDTO;
import cn.iocoder.yudao.module.system.api.sms.dto.SmsCodeUseReqDTO;
import cn.iocoder.yudao.module.system.service.sms.SmsCodeService;
import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated;
import javax.annotation.Resource;
/**
* 短信验证码 API 实现类
*
* @author 芋道源码
*/
@Service
@Validated
public class SmsCodeApiImpl implements SmsCodeApi {
@Resource
private SmsCodeService smsCodeService;
@Override
public void sendSmsCode(SmsCodeSendReqDTO reqDTO) {
smsCodeService.sendSmsCode(reqDTO);
}
@Override
public void useSmsCode(SmsCodeUseReqDTO reqDTO) {
smsCodeService.useSmsCode(reqDTO);
}
@Override
public void checkSmsCode(SmsCodeCheckReqDTO reqDTO) {
smsCodeService.checkSmsCode(reqDTO);
}
}

View File

@ -1,8 +1,11 @@
package cn.iocoder.yudao.module.system.service.sms; package cn.iocoder.yudao.module.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.module.system.api.sms.dto.SmsCodeCheckReqDTO;
import cn.iocoder.yudao.module.system.enums.sms.SmsSceneEnum; import cn.iocoder.yudao.module.system.api.sms.dto.SmsCodeSendReqDTO;
import cn.iocoder.yudao.module.system.api.sms.dto.SmsCodeUseReqDTO;
import javax.validation.Valid;
/** /**
* 短信验证码 Service 接口 * 短信验证码 Service 接口
@ -14,31 +17,24 @@ public interface SmsCodeService {
/** /**
* 创建短信验证码并进行发送 * 创建短信验证码并进行发送
* *
* @param mobile 手机号 * @param reqDTO 发送请求
* @param scene 发送场景 {@link SmsSceneEnum}
* @param createIp 发送 IP
*/ */
void sendSmsCode(@Mobile String mobile, Integer scene, String createIp); void sendSmsCode(@Valid SmsCodeSendReqDTO reqDTO);
/** /**
* 验证短信验证码并进行使用 * 验证短信验证码并进行使用
* 如果正确则将验证码标记成已使用 * 如果正确则将验证码标记成已使用
* 如果错误则抛出 {@link ServiceException} 异常 * 如果错误则抛出 {@link ServiceException} 异常
* *
* @param mobile 手机号 * @param reqDTO 使用请求
* @param scene 发送场景 {@link SmsSceneEnum}
* @param code 验证码
* @param usedIp 使用 IP
*/ */
void useSmsCode(@Mobile String mobile, Integer scene, String code, String usedIp); void useSmsCode(@Valid SmsCodeUseReqDTO reqDTO);
/** /**
* 检查验证码是否有效 * 检查验证码是否有效
* *
* @param mobile 手机 * @param reqDTO 校验请求
* @param code 验证码
* @param scene 使用场景
*/ */
void checkSmsCode(String mobile, String code, Integer scene); void checkSmsCode(@Valid SmsCodeCheckReqDTO reqDTO);
} }

View File

@ -4,6 +4,9 @@ import cn.hutool.core.lang.Assert;
import cn.hutool.core.map.MapUtil; import cn.hutool.core.map.MapUtil;
import cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil; import cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil;
import cn.iocoder.yudao.module.member.api.user.MemberUserApi; import cn.iocoder.yudao.module.member.api.user.MemberUserApi;
import cn.iocoder.yudao.module.system.api.sms.dto.SmsCodeCheckReqDTO;
import cn.iocoder.yudao.module.system.api.sms.dto.SmsCodeSendReqDTO;
import cn.iocoder.yudao.module.system.api.sms.dto.SmsCodeUseReqDTO;
import cn.iocoder.yudao.module.system.dal.dataobject.sms.SmsCodeDO; import cn.iocoder.yudao.module.system.dal.dataobject.sms.SmsCodeDO;
import cn.iocoder.yudao.module.system.dal.mysql.sms.SmsCodeMapper; import cn.iocoder.yudao.module.system.dal.mysql.sms.SmsCodeMapper;
import cn.iocoder.yudao.module.system.enums.sms.SmsSceneEnum; import cn.iocoder.yudao.module.system.enums.sms.SmsSceneEnum;
@ -42,13 +45,13 @@ public class SmsCodeServiceImpl implements SmsCodeService {
private SmsSendService smsSendService; private SmsSendService smsSendService;
@Override @Override
public void sendSmsCode(String mobile, Integer scene, String createIp) { public void sendSmsCode(SmsCodeSendReqDTO reqDTO) {
SmsSceneEnum sceneEnum = SmsSceneEnum.getCodeByScene(scene); SmsSceneEnum sceneEnum = SmsSceneEnum.getCodeByScene(reqDTO.getScene());
Assert.notNull(sceneEnum, "验证码场景({}) 查找不到配置", scene); Assert.notNull(sceneEnum, "验证码场景({}) 查找不到配置", reqDTO.getScene());
// 创建验证码 // 创建验证码
String code = createSmsCode(mobile, scene, createIp); String code = createSmsCode(reqDTO.getMobile(), reqDTO.getScene(), reqDTO.getCreateIp());
// 发送验证码 // 发送验证码
smsSendService.sendSingleSms(mobile, null, null, smsSendService.sendSingleSms(reqDTO.getMobile(), null, null,
sceneEnum.getTemplateCode(), MapUtil.of("code", code)); sceneEnum.getTemplateCode(), MapUtil.of("code", code));
} }
@ -77,17 +80,17 @@ public class SmsCodeServiceImpl implements SmsCodeService {
} }
@Override @Override
public void useSmsCode(String mobile, Integer scene, String code, String usedIp) { public void useSmsCode(SmsCodeUseReqDTO reqDTO) {
// 检测验证码是否有效 // 检测验证码是否有效
SmsCodeDO lastSmsCode = this.checkSmsCode0(mobile, code, scene); SmsCodeDO lastSmsCode = this.checkSmsCode0(reqDTO.getMobile(), reqDTO.getCode(), reqDTO.getScene());
// 使用验证码 // 使用验证码
smsCodeMapper.updateById(SmsCodeDO.builder().id(lastSmsCode.getId()) smsCodeMapper.updateById(SmsCodeDO.builder().id(lastSmsCode.getId())
.used(true).usedTime(new Date()).usedIp(usedIp).build()); .used(true).usedTime(new Date()).usedIp(reqDTO.getUsedIp()).build());
} }
@Override @Override
public void checkSmsCode(String mobile, String code, Integer scene) { public void checkSmsCode(SmsCodeCheckReqDTO reqDTO) {
checkSmsCode0(mobile, code, scene); checkSmsCode0(reqDTO.getMobile(), reqDTO.getCode(), reqDTO.getScene());
} }
public SmsCodeDO checkSmsCode0(String mobile, String code, Integer scene) { public SmsCodeDO checkSmsCode0(String mobile, String code, Integer scene) {