|
@@ -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);
|
|
|
|
+
|
|
|
|
+ // 获取发送模板
|
|
|
|
+ String codeTemplate = SysSmsSceneEnum.getCodeByScene(scene);
|
|
|
|
+
|
|
|
|
+ // 如果是更换手机号发送验证码,则需要检测手机号是否被注册
|
|
|
|
+ if (SysSmsSceneEnum.CHANGE_MOBILE_BY_SMS.getScene().equals(scene)){
|
|
|
|
+ this.checkMobileIsRegister(mobile,scene);
|
|
|
|
+ }
|
|
|
|
+
|
|
// 发送验证码
|
|
// 发送验证码
|
|
- // TODO @宋天:这里可以拓展下 SysSmsSceneEnum,支持设置对应的短信模板编号(不同场景的短信文案是不同的)、是否要校验手机号已经注册。这样 Controller 就可以收口成一个接口了。相当于说,不同场景,不同策略
|
|
|
|
- smsCoreService.sendSingleSmsToMember(mobile, null, SysSmsTemplateCodeConstants.USER_SMS_LOGIN,
|
|
|
|
|
|
+ smsCoreService.sendSingleSmsToMember(mobile, null, codeTemplate,
|
|
MapUtil.of("code", code));
|
|
MapUtil.of("code", code));
|
|
-
|
|
|
|
- // 存储手机号与验证码到redis,用于标记
|
|
|
|
- // TODO @宋天:SysSmsCodeDO 表应该足够,无需增加额外的 redis 存储哇
|
|
|
|
- // TODO @宋天:Redis 相关的操作,不要散落到业务层,而是写一个它对应的 RedisDAO。这样,实现业务与技术的解耦
|
|
|
|
- // TODO @宋天:直接使用 code 作为 key,会存在 2 个问题:1)code 可能会冲突,多个手机号之间;2)缺少前缀。例如说 sms_code_${code}
|
|
|
|
- stringRedisTemplate.opsForValue().set(code,mobile,CODE_TIME, TimeUnit.MINUTES);
|
|
|
|
}
|
|
}
|
|
|
|
|
|
- @Override
|
|
|
|
- public void sendSmsNewCode(SysAuthSendSmsReqVO reqVO) {
|
|
|
|
|
|
+ public void checkMobileIsRegister(String mobile, Integer scene) {
|
|
// 检测手机号是否已被使用
|
|
// 检测手机号是否已被使用
|
|
- 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) { // 若验证码不存在,抛出异常
|
|
|
|
- throw exception(USER_SMS_CODE_NOT_FOUND);
|
|
|
|
- }
|
|
|
|
- if (System.currentTimeMillis() - lastSmsCode.getCreateTime().getTime()
|
|
|
|
- >= smsCodeProperties.getExpireTimes().toMillis()) { // 验证码已过期
|
|
|
|
- throw exception(USER_SMS_CODE_EXPIRED);
|
|
|
|
- }
|
|
|
|
- if (lastSmsCode.getUsed()) { // 验证码已使用
|
|
|
|
|
|
+
|
|
|
|
+ // 检测验证码是否有效
|
|
|
|
+ SysSmsCodeDO lastSmsCode = this.checkCodeIsExpired(mobile, code, scene);
|
|
|
|
+
|
|
|
|
+ // 判断验证码是否已被使用
|
|
|
|
+ if (Boolean.TRUE.equals(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;
|
|
|
|
+
|
|
|
|
+ }
|
|
|
|
+
|
|
}
|
|
}
|