迁移 user 模块的发送短信功能到 system 模块
This commit is contained in:
parent
4ffc2cb815
commit
f4a698bc57
@ -14,7 +14,7 @@
|
||||
<packaging>pom</packaging>
|
||||
|
||||
<modules>
|
||||
<!-- <module>system-application</module>-->
|
||||
<module>system-application</module>
|
||||
<module>system-sdk</module>
|
||||
<module>system-service-api</module>
|
||||
<module>system-service-impl</module>
|
||||
@ -22,7 +22,6 @@
|
||||
<module>system-rpc</module>
|
||||
<module>system-rest</module>
|
||||
<module>system-biz</module>
|
||||
<module>system-application</module>
|
||||
</modules>
|
||||
|
||||
<dependencyManagement>
|
||||
|
@ -24,6 +24,13 @@ public enum SystemErrorCodeEnum implements ServiceExceptionUtil.Enumerable {
|
||||
// OAUTH_INVALID_REFRESH_TOKEN_EXPIRED(1002001018, "访问令牌已过期"),
|
||||
// OAUTH_INVALID_REFRESH_TOKEN_INVALID(1002001019, "刷新令牌已失效"),
|
||||
|
||||
// ========== OAuth 手机验证码模块 ==========
|
||||
OAUTH2_MOBILE_CODE_NOT_FOUND(1001001100, "验证码不存在"),
|
||||
OAUTH2_MOBILE_CODE_EXPIRED(1001001101, "验证码已过期"),
|
||||
OAUTH2_MOBILE_CODE_USED(1001001102, "验证码已使用"),
|
||||
OAUTH2_MOBILE_CODE_NOT_CORRECT(1001001104, "验证码不正确"),
|
||||
OAUTH2_MOBILE_CODE_EXCEED_SEND_MAXIMUM_QUANTITY_PER_DAY(1001001105, "超过每日短信发送数量"),
|
||||
OAUTH2_MOBILE_CODE_SEND_TOO_FAST(1001001106, "短信发送过于频率"),
|
||||
|
||||
// ========== 管理员模块 1002002000 ==========
|
||||
ADMIN_NOT_FOUND(1002002000, "管理员不存在"),
|
||||
|
@ -1,12 +1,12 @@
|
||||
package cn.iocoder.mall.user.biz.dao;
|
||||
package cn.iocoder.mall.system.biz.dao.oauth2;
|
||||
|
||||
import cn.iocoder.mall.user.biz.dataobject.MobileCodeDO;
|
||||
import cn.iocoder.mall.system.biz.dataobject.oauth2.OAuth2MobileCodeDO;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
@Repository // 实际不加也没问entity,就是不想 IDEA 那看到有个报错
|
||||
public interface MobileCodeMapper extends BaseMapper<MobileCodeDO> {
|
||||
@Repository
|
||||
public interface OAuth2MobileCodeMapper extends BaseMapper<OAuth2MobileCodeDO> {
|
||||
|
||||
/**
|
||||
* 获得手机号的最后一个手机验证码
|
||||
@ -14,8 +14,8 @@ public interface MobileCodeMapper extends BaseMapper<MobileCodeDO> {
|
||||
* @param mobile 手机号
|
||||
* @return 手机验证码
|
||||
*/
|
||||
default MobileCodeDO selectLast1ByMobile(String mobile) {
|
||||
QueryWrapper<MobileCodeDO> query = new QueryWrapper<MobileCodeDO>()
|
||||
default OAuth2MobileCodeDO selectLastByMobile(String mobile) {
|
||||
QueryWrapper<OAuth2MobileCodeDO> query = new QueryWrapper<OAuth2MobileCodeDO>()
|
||||
.eq("mobile", mobile)
|
||||
.orderByDesc("id")
|
||||
.last("limit 1");
|
@ -0,0 +1,57 @@
|
||||
package cn.iocoder.mall.system.biz.dataobject.oauth2;
|
||||
|
||||
import cn.iocoder.common.framework.dataobject.BaseDO;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* OAuth2 手机验证码
|
||||
*/
|
||||
@TableName("oauth2_mobile_code")
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@Accessors(chain = true)
|
||||
public class OAuth2MobileCodeDO extends BaseDO {
|
||||
|
||||
/**
|
||||
* 编号
|
||||
*/
|
||||
private Integer id;
|
||||
/**
|
||||
* 手机号
|
||||
*/
|
||||
private String mobile;
|
||||
/**
|
||||
* 验证码
|
||||
*/
|
||||
private String code;
|
||||
/**
|
||||
* 创建 IP
|
||||
*/
|
||||
private String createIp;
|
||||
/**
|
||||
* 今日发送的第几条
|
||||
*/
|
||||
private Integer todayIndex;
|
||||
/**
|
||||
* 是否使用
|
||||
*/
|
||||
private Boolean used;
|
||||
/**
|
||||
* 使用的账号编号
|
||||
*/
|
||||
private Integer usedAccountId;
|
||||
/**
|
||||
* 使用时间
|
||||
*/
|
||||
private Date usedTime;
|
||||
/**
|
||||
* 使用 IP
|
||||
*/
|
||||
private Date usedIp;
|
||||
|
||||
}
|
@ -0,0 +1,14 @@
|
||||
package cn.iocoder.mall.system.biz.dto.oatuh2;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
// TODO 注释
|
||||
@Data
|
||||
@Accessors(chain = true)
|
||||
public class OAuth2MobileCodeAuthenticateDTO {
|
||||
|
||||
private String mobile;
|
||||
private String code;
|
||||
|
||||
}
|
@ -0,0 +1,14 @@
|
||||
package cn.iocoder.mall.system.biz.dto.oatuh2;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
// TODO 注释
|
||||
@Data
|
||||
@Accessors(chain = true)
|
||||
public class OAuth2MobileCodeSendDTO {
|
||||
|
||||
private String mobile;
|
||||
private String ip;
|
||||
|
||||
}
|
@ -1 +0,0 @@
|
||||
package cn.iocoder.mall.system.biz.dto;
|
@ -2,6 +2,9 @@ package cn.iocoder.mall.system.biz.service.admin;
|
||||
|
||||
import cn.iocoder.mall.system.biz.bo.admin.AdminBO;
|
||||
|
||||
/**
|
||||
* 管理员 Service 接口
|
||||
*/
|
||||
public interface AdminService {
|
||||
|
||||
AdminBO get(Integer id);
|
||||
|
@ -0,0 +1,14 @@
|
||||
package cn.iocoder.mall.system.biz.service.oauth2;
|
||||
|
||||
import cn.iocoder.mall.system.biz.dto.oatuh2.OAuth2MobileCodeSendDTO;
|
||||
|
||||
/**
|
||||
* OAuth2 手机验证码 Service 接口
|
||||
*
|
||||
* 我们将手机验证码登陆的方式,作为一种拓展的 OAuth2 的认证方式。因此,我们放在了 `oauth2` 包下
|
||||
*/
|
||||
public interface OAuth2MobileCodeService {
|
||||
|
||||
void sendMobileCode(OAuth2MobileCodeSendDTO sendDTO);
|
||||
|
||||
}
|
@ -1,6 +1,7 @@
|
||||
package cn.iocoder.mall.system.biz.service.oauth2;
|
||||
|
||||
import cn.iocoder.mall.system.biz.bo.ouath2.OAuth2AccessTokenBO;
|
||||
import cn.iocoder.mall.system.biz.dto.oatuh2.OAuth2MobileCodeAuthenticateDTO;
|
||||
import cn.iocoder.mall.system.biz.dto.oatuh2.OAuth2UsernameAuthenticateDTO;
|
||||
|
||||
/**
|
||||
@ -10,4 +11,6 @@ public interface OAuth2Service {
|
||||
|
||||
OAuth2AccessTokenBO authenticate(OAuth2UsernameAuthenticateDTO usernameAuthenticateDTO);
|
||||
|
||||
OAuth2AccessTokenBO authenticate(OAuth2MobileCodeAuthenticateDTO mobileCodeAuthenticateDTO);
|
||||
|
||||
}
|
||||
|
@ -0,0 +1,67 @@
|
||||
package cn.iocoder.mall.system.biz.service.oauth2.impl;
|
||||
|
||||
import cn.iocoder.common.framework.constant.SysErrorCodeEnum;
|
||||
import cn.iocoder.common.framework.util.ServiceExceptionUtil;
|
||||
import cn.iocoder.common.framework.util.ValidationUtil;
|
||||
import cn.iocoder.mall.system.biz.constant.SystemErrorCodeEnum;
|
||||
import cn.iocoder.mall.system.biz.dao.oauth2.OAuth2MobileCodeMapper;
|
||||
import cn.iocoder.mall.system.biz.dataobject.oauth2.OAuth2MobileCodeDO;
|
||||
import cn.iocoder.mall.system.biz.dto.oatuh2.OAuth2MobileCodeSendDTO;
|
||||
import cn.iocoder.mall.system.biz.service.oauth2.OAuth2MobileCodeService;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
@Service
|
||||
public class OAuth2MobileCodeServiceImpl implements OAuth2MobileCodeService {
|
||||
|
||||
/**
|
||||
* 每条验证码的过期时间,单位:毫秒
|
||||
*/
|
||||
@Value("${modules.oauth2-mobile-code-service.code-expire-time-millis}")
|
||||
private int codeExpireTimes;
|
||||
/**
|
||||
* 每日发送最大数量
|
||||
*/
|
||||
@Value("${modules.oauth2-mobile-code-service.send-maximum-quantity-per-day}")
|
||||
private int sendMaximumQuantityPerDay;
|
||||
/**
|
||||
* 短信发送频率,单位:毫秒
|
||||
*/
|
||||
@Value("${modules.oauth2-mobile-code-service.send-frequency}")
|
||||
private int sendFrequency;
|
||||
|
||||
@Autowired
|
||||
private OAuth2MobileCodeMapper oauth2MobileCodeMapper;
|
||||
|
||||
@Override
|
||||
public void sendMobileCode(OAuth2MobileCodeSendDTO sendDTO) {
|
||||
if (!ValidationUtil.isMobile(sendDTO.getMobile())) {
|
||||
throw ServiceExceptionUtil.exception(SysErrorCodeEnum.VALIDATION_REQUEST_PARAM_ERROR.getCode(), "手机格式不正确"); // TODO 有点搓
|
||||
}
|
||||
// 校验是否可以发送验证码
|
||||
OAuth2MobileCodeDO lastMobileCodePO = oauth2MobileCodeMapper.selectLastByMobile(sendDTO.getMobile());
|
||||
if (lastMobileCodePO != null) {
|
||||
if (lastMobileCodePO.getTodayIndex() >= sendMaximumQuantityPerDay) { // 超过当天发送的上限。
|
||||
throw ServiceExceptionUtil.exception(SystemErrorCodeEnum.OAUTH2_MOBILE_CODE_EXCEED_SEND_MAXIMUM_QUANTITY_PER_DAY.getCode());
|
||||
}
|
||||
if (System.currentTimeMillis() - lastMobileCodePO.getCreateTime().getTime() < sendFrequency) { // 发送过于频繁
|
||||
throw ServiceExceptionUtil.exception(SystemErrorCodeEnum.OAUTH2_MOBILE_CODE_SEND_TOO_FAST.getCode());
|
||||
}
|
||||
// TODO 提升,每个 IP 每天可发送数量
|
||||
// TODO 提升,每个 IP 每小时可发送数量
|
||||
}
|
||||
// 创建验证码记录
|
||||
OAuth2MobileCodeDO newMobileCodePO = new OAuth2MobileCodeDO().setMobile(sendDTO.getMobile())
|
||||
.setCode("9999") // TODO 芋艿,随机 4 位验证码 or 6 位验证码
|
||||
.setTodayIndex(lastMobileCodePO != null ? lastMobileCodePO.getTodayIndex() : 1)
|
||||
.setCreateIp(sendDTO.getIp())
|
||||
.setUsed(false);
|
||||
newMobileCodePO.setCreateTime(new Date());
|
||||
oauth2MobileCodeMapper.insert(newMobileCodePO);
|
||||
// TODO 发送验证码短信
|
||||
}
|
||||
|
||||
}
|
@ -8,6 +8,7 @@ import cn.iocoder.mall.system.biz.dao.oauth2.OAuth2AccessTokenMapper;
|
||||
import cn.iocoder.mall.system.biz.dao.oauth2.OAuth2RefreshTokenMapper;
|
||||
import cn.iocoder.mall.system.biz.dataobject.oauth2.OAuth2AccessTokenDO;
|
||||
import cn.iocoder.mall.system.biz.dataobject.oauth2.OAuth2RefreshTokenDO;
|
||||
import cn.iocoder.mall.system.biz.dto.oatuh2.OAuth2MobileCodeAuthenticateDTO;
|
||||
import cn.iocoder.mall.system.biz.dto.oatuh2.OAuth2UsernameAuthenticateDTO;
|
||||
import cn.iocoder.mall.system.biz.service.account.AccountService;
|
||||
import cn.iocoder.mall.system.biz.service.oauth2.OAuth2Service;
|
||||
@ -63,6 +64,11 @@ public class OAuth2ServiceImpl implements OAuth2Service {
|
||||
return OAuth2Convert.INSTANCE.convert(oauth2AccessTokenDO);
|
||||
}
|
||||
|
||||
@Override
|
||||
public OAuth2AccessTokenBO authenticate(OAuth2MobileCodeAuthenticateDTO mobileCodeAuthenticateDTO) {
|
||||
return null;
|
||||
}
|
||||
|
||||
private OAuth2AccessTokenDO createOAuth2AccessToken(Integer accountId, String refreshToken) {
|
||||
OAuth2AccessTokenDO accessToken = new OAuth2AccessTokenDO()
|
||||
.setId(generateAccessToken())
|
||||
|
@ -0,0 +1,10 @@
|
||||
package cn.iocoder.mall.system.biz.service.user;
|
||||
|
||||
/**
|
||||
* 用户 Service 接口
|
||||
*/
|
||||
public interface UserService {
|
||||
|
||||
|
||||
|
||||
}
|
@ -0,0 +1,8 @@
|
||||
package cn.iocoder.mall.system.biz.service.user.impl;
|
||||
|
||||
import cn.iocoder.mall.system.biz.service.user.UserService;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
@Service
|
||||
public class UserServiceImpl implements UserService {
|
||||
}
|
@ -1,4 +1,8 @@
|
||||
##################### 业务模块 #####################
|
||||
## OAuth2CodeService
|
||||
modules.oauth2-code-service.access-token-expire-time-millis = 2880000
|
||||
modules.oauth2-code-service.refresh-token-expire-time-millis = 43200000
|
||||
modules.oauth2-code-service.refresh-token-expire-time-millis = 43200000
|
||||
## OAuth2MobileCodeService
|
||||
modules.oauth2-mobile-code-service.code-expire-time-millis = 600000
|
||||
modules.oauth2-mobile-code-service.send-maximum-quantity-per-day = 10
|
||||
modules.oauth2-mobile-code-service.send-frequency = 60000
|
||||
|
@ -0,0 +1,46 @@
|
||||
package cn.iocoder.mall.system.rest.controller.users;
|
||||
|
||||
import cn.iocoder.common.framework.constant.MallConstants;
|
||||
import cn.iocoder.common.framework.util.HttpUtil;
|
||||
import cn.iocoder.common.framework.vo.CommonResult;
|
||||
import cn.iocoder.mall.system.biz.dto.oatuh2.OAuth2MobileCodeSendDTO;
|
||||
import cn.iocoder.mall.system.biz.service.oauth2.OAuth2MobileCodeService;
|
||||
import cn.iocoder.mall.system.biz.service.oauth2.OAuth2Service;
|
||||
import cn.iocoder.mall.system.biz.service.user.UserService;
|
||||
import io.swagger.annotations.Api;
|
||||
import io.swagger.annotations.ApiImplicitParam;
|
||||
import io.swagger.annotations.ApiOperation;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
@RestController
|
||||
@RequestMapping(MallConstants.ROOT_PATH_USER + "/oauth2")
|
||||
@Api(tags = "用户 - OAuth2 API")
|
||||
public class UsersOAuth2Controller {
|
||||
|
||||
@Autowired
|
||||
private OAuth2Service oauth2Service;
|
||||
@Autowired
|
||||
private UserService userService;
|
||||
@Autowired
|
||||
private OAuth2MobileCodeService oauth2MobileCodeService;
|
||||
|
||||
@PostMapping("/send_mobile_code")
|
||||
@ApiOperation("发送手机验证码")
|
||||
@ApiImplicitParam(name = "mobile", value = "手机号", required = true, example = "15601691234")
|
||||
public CommonResult<Boolean> sendMobileCode(@RequestParam("mobile") String mobile,
|
||||
HttpServletRequest request) {
|
||||
// 执行发送验证码
|
||||
OAuth2MobileCodeSendDTO sendDTO = new OAuth2MobileCodeSendDTO()
|
||||
.setMobile(mobile).setIp(HttpUtil.getIp(request));
|
||||
oauth2MobileCodeService.sendMobileCode(sendDTO);
|
||||
// 返回成功
|
||||
return CommonResult.success(true);
|
||||
}
|
||||
|
||||
}
|
@ -27,13 +27,7 @@ public enum UserErrorCodeEnum {
|
||||
USER_STATUS_EQUALS(1001002003, "账号已经是该状态"),
|
||||
USER_MOBILE_EQUALS(1001002004, "账号已经是该手机号"),
|
||||
|
||||
// ========== 手机验证码模块 ==========
|
||||
MOBILE_CODE_NOT_FOUND(1001003000, "验证码不存在"),
|
||||
MOBILE_CODE_EXPIRED(1001003001, "验证码已过期"),
|
||||
MOBILE_CODE_USED(1001003002, "验证码已使用"),
|
||||
MOBILE_CODE_NOT_CORRECT(1001003003, "验证码不正确"),
|
||||
MOBILE_CODE_EXCEED_SEND_MAXIMUM_QUANTITY_PER_DAY(1001003004, "超过每日短信发送数量"),
|
||||
MOBILE_CODE_SEND_TOO_FAST(1001003005, "短信发送过于频率"),
|
||||
|
||||
|
||||
// ========== 用户地址 ==========
|
||||
USER_ADDRESS_NOT_EXISTENT(1001004000, "用户地址不存在!"),
|
||||
|
@ -49,7 +49,6 @@ public class MobileCodeServiceImpl implements MobileCodeService {
|
||||
* @return 手机验证码信息
|
||||
*/
|
||||
public MobileCodeDO validLastMobileCode(String mobile, String code) {
|
||||
// TODO: 2019-04-09 Sin 暂时先忽略掉验证码校验
|
||||
// return new MobileCodeDO().setCode(code).setCreateTime(new Date()).setId(1);
|
||||
MobileCodeDO mobileCodePO = mobileCodeMapper.selectLast1ByMobile(mobile);
|
||||
if (mobileCodePO == null) { // 若验证码不存在,抛出异常
|
||||
@ -78,31 +77,4 @@ public class MobileCodeServiceImpl implements MobileCodeService {
|
||||
mobileCodeMapper.updateById(update);
|
||||
}
|
||||
|
||||
// TODO 芋艿,后面要返回有效时间
|
||||
public void send(String mobile) {
|
||||
if (!ValidationUtil.isMobile(mobile)) {
|
||||
throw ServiceExceptionUtil.exception(SysErrorCodeEnum.VALIDATION_REQUEST_PARAM_ERROR.getCode(), "手机格式不正确"); // TODO 有点搓
|
||||
}
|
||||
// 校验是否可以发送验证码
|
||||
MobileCodeDO lastMobileCodePO = mobileCodeMapper.selectLast1ByMobile(mobile);
|
||||
if (lastMobileCodePO != null) {
|
||||
if (lastMobileCodePO.getTodayIndex() >= sendMaximumQuantityPerDay) { // 超过当天发送的上限。
|
||||
throw ServiceExceptionUtil.exception(UserErrorCodeEnum.MOBILE_CODE_EXCEED_SEND_MAXIMUM_QUANTITY_PER_DAY.getCode());
|
||||
}
|
||||
if (System.currentTimeMillis() - lastMobileCodePO.getCreateTime().getTime() < sendFrequency) { // 发送过于频繁
|
||||
throw ServiceExceptionUtil.exception(UserErrorCodeEnum.MOBILE_CODE_SEND_TOO_FAST.getCode());
|
||||
}
|
||||
// TODO 提升,每个 IP 每天可发送数量
|
||||
// TODO 提升,每个 IP 每小时可发送数量
|
||||
}
|
||||
// 创建验证码记录
|
||||
MobileCodeDO newMobileCodePO = new MobileCodeDO().setMobile(mobile)
|
||||
.setCode("9999") // TODO 芋艿,随机 4 位验证码 or 6 位验证码
|
||||
.setTodayIndex(lastMobileCodePO != null ? lastMobileCodePO.getTodayIndex() : 1)
|
||||
.setUsed(false);
|
||||
newMobileCodePO.setCreateTime(new Date());
|
||||
mobileCodeMapper.insert(newMobileCodePO);
|
||||
// TODO 发送验证码短信
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,5 +1 @@
|
||||
##################### 业务模块 #####################
|
||||
## MobileCodeService
|
||||
modules.mobile-code-service.code-expire-time-millis = 600000
|
||||
modules.mobile-code-service.send-maximum-quantity-per-day = 10
|
||||
modules.mobile-code-service.send-frequency = 60000
|
||||
|
Loading…
Reference in New Issue
Block a user