增加 user 使用 mobile 认证的逻辑
This commit is contained in:
parent
f4a698bc57
commit
220984c45b
@ -0,0 +1,18 @@
|
|||||||
|
package cn.iocoder.mall.system.biz.bo.user;
|
||||||
|
|
||||||
|
import cn.iocoder.mall.system.biz.bo.ouath2.OAuth2AccessTokenBO;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.experimental.Accessors;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* TODO 注释
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@Accessors(chain = true)
|
||||||
|
public class UserAuthenticateBO {
|
||||||
|
|
||||||
|
private UserBO user;
|
||||||
|
|
||||||
|
private OAuth2AccessTokenBO token;
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,26 @@
|
|||||||
|
package cn.iocoder.mall.system.biz.bo.user;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.experimental.Accessors;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* TODO 注释
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@Accessors(chain = true)
|
||||||
|
public class UserBO {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 用户编号
|
||||||
|
*/
|
||||||
|
private Integer id;
|
||||||
|
/**
|
||||||
|
* 昵称
|
||||||
|
*/
|
||||||
|
private String nickname;
|
||||||
|
/**
|
||||||
|
* 头像
|
||||||
|
*/
|
||||||
|
private String avatar;
|
||||||
|
|
||||||
|
}
|
@ -32,6 +32,7 @@ public enum SystemErrorCodeEnum implements ServiceExceptionUtil.Enumerable {
|
|||||||
OAUTH2_MOBILE_CODE_EXCEED_SEND_MAXIMUM_QUANTITY_PER_DAY(1001001105, "超过每日短信发送数量"),
|
OAUTH2_MOBILE_CODE_EXCEED_SEND_MAXIMUM_QUANTITY_PER_DAY(1001001105, "超过每日短信发送数量"),
|
||||||
OAUTH2_MOBILE_CODE_SEND_TOO_FAST(1001001106, "短信发送过于频率"),
|
OAUTH2_MOBILE_CODE_SEND_TOO_FAST(1001001106, "短信发送过于频率"),
|
||||||
|
|
||||||
|
|
||||||
// ========== 管理员模块 1002002000 ==========
|
// ========== 管理员模块 1002002000 ==========
|
||||||
ADMIN_NOT_FOUND(1002002000, "管理员不存在"),
|
ADMIN_NOT_FOUND(1002002000, "管理员不存在"),
|
||||||
// 废弃 ADMIN_USERNAME_NOT_REGISTERED(1002002000, "账号不存在"),
|
// 废弃 ADMIN_USERNAME_NOT_REGISTERED(1002002000, "账号不存在"),
|
||||||
|
@ -2,6 +2,7 @@ package cn.iocoder.mall.system.biz.convert;
|
|||||||
|
|
||||||
import cn.iocoder.mall.system.biz.bo.account.AccountBO;
|
import cn.iocoder.mall.system.biz.bo.account.AccountBO;
|
||||||
import cn.iocoder.mall.system.biz.dataobject.account.AccountDO;
|
import cn.iocoder.mall.system.biz.dataobject.account.AccountDO;
|
||||||
|
import cn.iocoder.mall.system.biz.dto.account.AccountCreateDTO;
|
||||||
import org.mapstruct.Mapper;
|
import org.mapstruct.Mapper;
|
||||||
import org.mapstruct.factory.Mappers;
|
import org.mapstruct.factory.Mappers;
|
||||||
|
|
||||||
@ -12,4 +13,6 @@ public interface AccountConvert {
|
|||||||
|
|
||||||
AccountBO convert(AccountDO accountDO);
|
AccountBO convert(AccountDO accountDO);
|
||||||
|
|
||||||
|
AccountDO convert(AccountCreateDTO accountCreateDTO);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,22 @@
|
|||||||
|
package cn.iocoder.mall.system.biz.convert;
|
||||||
|
|
||||||
|
import cn.iocoder.mall.system.biz.bo.ouath2.OAuth2AccessTokenBO;
|
||||||
|
import cn.iocoder.mall.system.biz.bo.user.UserAuthenticateBO;
|
||||||
|
import cn.iocoder.mall.system.biz.bo.user.UserBO;
|
||||||
|
import cn.iocoder.mall.system.biz.dataobject.user.UserDO;
|
||||||
|
import org.mapstruct.Mapper;
|
||||||
|
import org.mapstruct.Mapping;
|
||||||
|
import org.mapstruct.factory.Mappers;
|
||||||
|
|
||||||
|
@Mapper
|
||||||
|
public interface UserConvert {
|
||||||
|
|
||||||
|
UserConvert INSTANCE = Mappers.getMapper(UserConvert.class);
|
||||||
|
|
||||||
|
@Mapping(source = "userBO", target = "user")
|
||||||
|
@Mapping(source = "accessTokenBO", target = "token")
|
||||||
|
UserAuthenticateBO convert(UserBO userBO, OAuth2AccessTokenBO accessTokenBO);
|
||||||
|
|
||||||
|
UserBO convert(UserDO userDO);
|
||||||
|
|
||||||
|
}
|
@ -14,4 +14,10 @@ public interface AccountMapper extends BaseMapper<AccountDO> {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
default AccountDO selectByMobile(String mobile) {
|
||||||
|
return selectOne(new QueryWrapper<AccountDO>()
|
||||||
|
.eq("mobile", mobile)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,17 @@
|
|||||||
|
package cn.iocoder.mall.system.biz.dao.user;
|
||||||
|
|
||||||
|
import cn.iocoder.mall.system.biz.dataobject.user.UserDO;
|
||||||
|
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||||
|
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||||
|
import org.springframework.stereotype.Repository;
|
||||||
|
|
||||||
|
@Repository
|
||||||
|
public interface UserMapper extends BaseMapper<UserDO> {
|
||||||
|
|
||||||
|
default UserDO selectByAccountId(Integer accountId) {
|
||||||
|
return selectOne(new QueryWrapper<UserDO>()
|
||||||
|
.eq("account_id", accountId)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -1,5 +1,6 @@
|
|||||||
package cn.iocoder.mall.system.biz.dataobject.account;
|
package cn.iocoder.mall.system.biz.dataobject.account;
|
||||||
|
|
||||||
|
import cn.iocoder.common.framework.constant.CommonStatusEnum;
|
||||||
import cn.iocoder.common.framework.dataobject.DeletableDO;
|
import cn.iocoder.common.framework.dataobject.DeletableDO;
|
||||||
import com.baomidou.mybatisplus.annotation.TableName;
|
import com.baomidou.mybatisplus.annotation.TableName;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
@ -42,7 +43,7 @@ public class AccountDO extends DeletableDO {
|
|||||||
/**
|
/**
|
||||||
* 账号状态
|
* 账号状态
|
||||||
*
|
*
|
||||||
* {@link cn.iocoder.common.framework.constant.CommonStatusEnum}
|
* 枚举 {@link CommonStatusEnum}
|
||||||
*/
|
*/
|
||||||
private Integer status;
|
private Integer status;
|
||||||
|
|
||||||
|
@ -41,10 +41,6 @@ public class OAuth2MobileCodeDO extends BaseDO {
|
|||||||
* 是否使用
|
* 是否使用
|
||||||
*/
|
*/
|
||||||
private Boolean used;
|
private Boolean used;
|
||||||
/**
|
|
||||||
* 使用的账号编号
|
|
||||||
*/
|
|
||||||
private Integer usedAccountId;
|
|
||||||
/**
|
/**
|
||||||
* 使用时间
|
* 使用时间
|
||||||
*/
|
*/
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
package cn.iocoder.mall.system.biz.dataobject.user;
|
package cn.iocoder.mall.system.biz.dataobject.user;
|
||||||
|
|
||||||
import cn.iocoder.common.framework.dataobject.DeletableDO;
|
import cn.iocoder.common.framework.dataobject.BaseDO;
|
||||||
import cn.iocoder.mall.system.biz.dataobject.account.AccountDO;
|
import cn.iocoder.mall.system.biz.dataobject.account.AccountDO;
|
||||||
import com.baomidou.mybatisplus.annotation.TableName;
|
import com.baomidou.mybatisplus.annotation.TableName;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
@ -10,11 +10,11 @@ import lombok.experimental.Accessors;
|
|||||||
/**
|
/**
|
||||||
* 用户实体
|
* 用户实体
|
||||||
*/
|
*/
|
||||||
@TableName(value = "user")
|
@TableName(value = "users")
|
||||||
@Data
|
@Data
|
||||||
@EqualsAndHashCode(callSuper = true)
|
@EqualsAndHashCode(callSuper = true)
|
||||||
@Accessors(chain = true)
|
@Accessors(chain = true)
|
||||||
public class UserDO extends DeletableDO {
|
public class UserDO extends BaseDO {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 用户编号
|
* 用户编号
|
||||||
|
@ -0,0 +1,34 @@
|
|||||||
|
package cn.iocoder.mall.system.biz.dto.account;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.experimental.Accessors;
|
||||||
|
|
||||||
|
// TODO 注释
|
||||||
|
@Data
|
||||||
|
@Accessors(chain = true)
|
||||||
|
public class AccountCreateDTO {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 登陆账号
|
||||||
|
*/
|
||||||
|
private String username;
|
||||||
|
/**
|
||||||
|
* 手机号
|
||||||
|
*/
|
||||||
|
private String mobile;
|
||||||
|
/**
|
||||||
|
* 邮箱
|
||||||
|
*/
|
||||||
|
private String email;
|
||||||
|
/**
|
||||||
|
* 密码
|
||||||
|
*
|
||||||
|
* // TODO 芋艿 暂时明文
|
||||||
|
*/
|
||||||
|
private String password;
|
||||||
|
/**
|
||||||
|
* 创建 IP
|
||||||
|
*/
|
||||||
|
private String createIp;
|
||||||
|
|
||||||
|
}
|
@ -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 OAuth2MobileCodAuthenticateDTO {
|
||||||
|
|
||||||
|
private String mobile;
|
||||||
|
private String code;
|
||||||
|
|
||||||
|
}
|
@ -10,5 +10,6 @@ public class OAuth2MobileCodeAuthenticateDTO {
|
|||||||
|
|
||||||
private String mobile;
|
private String mobile;
|
||||||
private String code;
|
private String code;
|
||||||
|
private String ip;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
package cn.iocoder.mall.system.biz.service.account;
|
package cn.iocoder.mall.system.biz.service.account;
|
||||||
|
|
||||||
import cn.iocoder.mall.system.biz.bo.account.AccountBO;
|
import cn.iocoder.mall.system.biz.bo.account.AccountBO;
|
||||||
|
import cn.iocoder.mall.system.biz.dto.account.AccountCreateDTO;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 账号 Service 接口
|
* 账号 Service 接口
|
||||||
@ -9,6 +10,10 @@ public interface AccountService {
|
|||||||
|
|
||||||
AccountBO getByUsername(String username);
|
AccountBO getByUsername(String username);
|
||||||
|
|
||||||
|
AccountBO getByMobile(String mobile);
|
||||||
|
|
||||||
boolean matchPassword(String rawPassword, String encodedPassword);
|
boolean matchPassword(String rawPassword, String encodedPassword);
|
||||||
|
|
||||||
|
AccountBO create(AccountCreateDTO createDTO);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1,13 +1,16 @@
|
|||||||
package cn.iocoder.mall.system.biz.service.account.impl;
|
package cn.iocoder.mall.system.biz.service.account.impl;
|
||||||
|
|
||||||
|
import cn.iocoder.common.framework.constant.CommonStatusEnum;
|
||||||
import cn.iocoder.mall.system.biz.bo.account.AccountBO;
|
import cn.iocoder.mall.system.biz.bo.account.AccountBO;
|
||||||
import cn.iocoder.mall.system.biz.convert.AccountConvert;
|
import cn.iocoder.mall.system.biz.convert.AccountConvert;
|
||||||
import cn.iocoder.mall.system.biz.dao.account.AccountMapper;
|
import cn.iocoder.mall.system.biz.dao.account.AccountMapper;
|
||||||
import cn.iocoder.mall.system.biz.dataobject.account.AccountDO;
|
import cn.iocoder.mall.system.biz.dataobject.account.AccountDO;
|
||||||
|
import cn.iocoder.mall.system.biz.dto.account.AccountCreateDTO;
|
||||||
import cn.iocoder.mall.system.biz.service.account.AccountService;
|
import cn.iocoder.mall.system.biz.service.account.AccountService;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
import java.util.Date;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
|
|
||||||
@Service
|
@Service
|
||||||
@ -22,9 +25,26 @@ public class AccountServiceImpl implements AccountService {
|
|||||||
return AccountConvert.INSTANCE.convert(accountDO);
|
return AccountConvert.INSTANCE.convert(accountDO);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public AccountBO getByMobile(String mobile) {
|
||||||
|
AccountDO accountDO = accountMapper.selectByMobile(mobile);
|
||||||
|
return AccountConvert.INSTANCE.convert(accountDO);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean matchPassword(String rawPassword, String encodedPassword) {
|
public boolean matchPassword(String rawPassword, String encodedPassword) {
|
||||||
return Objects.equals(rawPassword, encodedPassword);
|
return Objects.equals(rawPassword, encodedPassword);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public AccountBO create(AccountCreateDTO createDTO) {
|
||||||
|
// 插入
|
||||||
|
AccountDO accountDO = AccountConvert.INSTANCE.convert(createDTO);
|
||||||
|
accountDO.setStatus(CommonStatusEnum.ENABLE.getValue());
|
||||||
|
accountDO.setCreateTime(new Date());
|
||||||
|
accountMapper.insert(accountDO);
|
||||||
|
// 转换返回
|
||||||
|
return AccountConvert.INSTANCE.convert(accountDO);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -9,6 +9,8 @@ import cn.iocoder.mall.system.biz.dto.oatuh2.OAuth2MobileCodeSendDTO;
|
|||||||
*/
|
*/
|
||||||
public interface OAuth2MobileCodeService {
|
public interface OAuth2MobileCodeService {
|
||||||
|
|
||||||
void sendMobileCode(OAuth2MobileCodeSendDTO sendDTO);
|
void send(OAuth2MobileCodeSendDTO sendDTO);
|
||||||
|
|
||||||
|
void use(String mobile, String code);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -9,8 +9,8 @@ import cn.iocoder.mall.system.biz.dto.oatuh2.OAuth2UsernameAuthenticateDTO;
|
|||||||
*/
|
*/
|
||||||
public interface OAuth2Service {
|
public interface OAuth2Service {
|
||||||
|
|
||||||
OAuth2AccessTokenBO authenticate(OAuth2UsernameAuthenticateDTO usernameAuthenticateDTO);
|
OAuth2AccessTokenBO authenticate(OAuth2UsernameAuthenticateDTO authenticateDTO);
|
||||||
|
|
||||||
OAuth2AccessTokenBO authenticate(OAuth2MobileCodeAuthenticateDTO mobileCodeAuthenticateDTO);
|
OAuth2AccessTokenBO authenticate(OAuth2MobileCodeAuthenticateDTO authenticateDTO);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -3,7 +3,6 @@ package cn.iocoder.mall.system.biz.service.oauth2.impl;
|
|||||||
import cn.iocoder.common.framework.constant.SysErrorCodeEnum;
|
import cn.iocoder.common.framework.constant.SysErrorCodeEnum;
|
||||||
import cn.iocoder.common.framework.util.ServiceExceptionUtil;
|
import cn.iocoder.common.framework.util.ServiceExceptionUtil;
|
||||||
import cn.iocoder.common.framework.util.ValidationUtil;
|
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.dao.oauth2.OAuth2MobileCodeMapper;
|
||||||
import cn.iocoder.mall.system.biz.dataobject.oauth2.OAuth2MobileCodeDO;
|
import cn.iocoder.mall.system.biz.dataobject.oauth2.OAuth2MobileCodeDO;
|
||||||
import cn.iocoder.mall.system.biz.dto.oatuh2.OAuth2MobileCodeSendDTO;
|
import cn.iocoder.mall.system.biz.dto.oatuh2.OAuth2MobileCodeSendDTO;
|
||||||
@ -14,6 +13,8 @@ import org.springframework.stereotype.Service;
|
|||||||
|
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
|
|
||||||
|
import static cn.iocoder.mall.system.biz.constant.SystemErrorCodeEnum.*;
|
||||||
|
|
||||||
@Service
|
@Service
|
||||||
public class OAuth2MobileCodeServiceImpl implements OAuth2MobileCodeService {
|
public class OAuth2MobileCodeServiceImpl implements OAuth2MobileCodeService {
|
||||||
|
|
||||||
@ -37,7 +38,7 @@ public class OAuth2MobileCodeServiceImpl implements OAuth2MobileCodeService {
|
|||||||
private OAuth2MobileCodeMapper oauth2MobileCodeMapper;
|
private OAuth2MobileCodeMapper oauth2MobileCodeMapper;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void sendMobileCode(OAuth2MobileCodeSendDTO sendDTO) {
|
public void send(OAuth2MobileCodeSendDTO sendDTO) {
|
||||||
if (!ValidationUtil.isMobile(sendDTO.getMobile())) {
|
if (!ValidationUtil.isMobile(sendDTO.getMobile())) {
|
||||||
throw ServiceExceptionUtil.exception(SysErrorCodeEnum.VALIDATION_REQUEST_PARAM_ERROR.getCode(), "手机格式不正确"); // TODO 有点搓
|
throw ServiceExceptionUtil.exception(SysErrorCodeEnum.VALIDATION_REQUEST_PARAM_ERROR.getCode(), "手机格式不正确"); // TODO 有点搓
|
||||||
}
|
}
|
||||||
@ -45,10 +46,10 @@ public class OAuth2MobileCodeServiceImpl implements OAuth2MobileCodeService {
|
|||||||
OAuth2MobileCodeDO lastMobileCodePO = oauth2MobileCodeMapper.selectLastByMobile(sendDTO.getMobile());
|
OAuth2MobileCodeDO lastMobileCodePO = oauth2MobileCodeMapper.selectLastByMobile(sendDTO.getMobile());
|
||||||
if (lastMobileCodePO != null) {
|
if (lastMobileCodePO != null) {
|
||||||
if (lastMobileCodePO.getTodayIndex() >= sendMaximumQuantityPerDay) { // 超过当天发送的上限。
|
if (lastMobileCodePO.getTodayIndex() >= sendMaximumQuantityPerDay) { // 超过当天发送的上限。
|
||||||
throw ServiceExceptionUtil.exception(SystemErrorCodeEnum.OAUTH2_MOBILE_CODE_EXCEED_SEND_MAXIMUM_QUANTITY_PER_DAY.getCode());
|
throw ServiceExceptionUtil.exception(OAUTH2_MOBILE_CODE_EXCEED_SEND_MAXIMUM_QUANTITY_PER_DAY);
|
||||||
}
|
}
|
||||||
if (System.currentTimeMillis() - lastMobileCodePO.getCreateTime().getTime() < sendFrequency) { // 发送过于频繁
|
if (System.currentTimeMillis() - lastMobileCodePO.getCreateTime().getTime() < sendFrequency) { // 发送过于频繁
|
||||||
throw ServiceExceptionUtil.exception(SystemErrorCodeEnum.OAUTH2_MOBILE_CODE_SEND_TOO_FAST.getCode());
|
throw ServiceExceptionUtil.exception(OAUTH2_MOBILE_CODE_SEND_TOO_FAST);
|
||||||
}
|
}
|
||||||
// TODO 提升,每个 IP 每天可发送数量
|
// TODO 提升,每个 IP 每天可发送数量
|
||||||
// TODO 提升,每个 IP 每小时可发送数量
|
// TODO 提升,每个 IP 每小时可发送数量
|
||||||
@ -64,4 +65,26 @@ public class OAuth2MobileCodeServiceImpl implements OAuth2MobileCodeService {
|
|||||||
// TODO 发送验证码短信
|
// TODO 发送验证码短信
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void use(String mobile, String code) {
|
||||||
|
// 校验验证码
|
||||||
|
OAuth2MobileCodeDO mobileCodeDO = oauth2MobileCodeMapper.selectLastByMobile(mobile);
|
||||||
|
if (mobileCodeDO == null) { // 若验证码不存在,抛出异常
|
||||||
|
throw ServiceExceptionUtil.exception(OAUTH2_MOBILE_CODE_NOT_FOUND);
|
||||||
|
}
|
||||||
|
if (System.currentTimeMillis() - mobileCodeDO.getCreateTime().getTime() >= codeExpireTimes) { // 验证码已过期
|
||||||
|
throw ServiceExceptionUtil.exception(OAUTH2_MOBILE_CODE_EXPIRED);
|
||||||
|
}
|
||||||
|
if (mobileCodeDO.getUsed()) { // 验证码已使用
|
||||||
|
throw ServiceExceptionUtil.exception(OAUTH2_MOBILE_CODE_USED);
|
||||||
|
}
|
||||||
|
if (!mobileCodeDO.getCode().equals(code)) {
|
||||||
|
throw ServiceExceptionUtil.exception(OAUTH2_MOBILE_CODE_NOT_CORRECT);
|
||||||
|
}
|
||||||
|
// 使用验证码
|
||||||
|
OAuth2MobileCodeDO update = new OAuth2MobileCodeDO().setId(mobileCodeDO.getId())
|
||||||
|
.setUsed(true).setUsedTime(new Date()); // TODO usedIp
|
||||||
|
oauth2MobileCodeMapper.updateById(update);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
package cn.iocoder.mall.system.biz.service.oauth2.impl;
|
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.ServiceExceptionUtil;
|
||||||
|
import cn.iocoder.common.framework.util.ValidationUtil;
|
||||||
import cn.iocoder.mall.system.biz.bo.account.AccountBO;
|
import cn.iocoder.mall.system.biz.bo.account.AccountBO;
|
||||||
import cn.iocoder.mall.system.biz.bo.ouath2.OAuth2AccessTokenBO;
|
import cn.iocoder.mall.system.biz.bo.ouath2.OAuth2AccessTokenBO;
|
||||||
import cn.iocoder.mall.system.biz.convert.OAuth2Convert;
|
import cn.iocoder.mall.system.biz.convert.OAuth2Convert;
|
||||||
@ -8,9 +10,11 @@ import cn.iocoder.mall.system.biz.dao.oauth2.OAuth2AccessTokenMapper;
|
|||||||
import cn.iocoder.mall.system.biz.dao.oauth2.OAuth2RefreshTokenMapper;
|
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.OAuth2AccessTokenDO;
|
||||||
import cn.iocoder.mall.system.biz.dataobject.oauth2.OAuth2RefreshTokenDO;
|
import cn.iocoder.mall.system.biz.dataobject.oauth2.OAuth2RefreshTokenDO;
|
||||||
|
import cn.iocoder.mall.system.biz.dto.account.AccountCreateDTO;
|
||||||
import cn.iocoder.mall.system.biz.dto.oatuh2.OAuth2MobileCodeAuthenticateDTO;
|
import cn.iocoder.mall.system.biz.dto.oatuh2.OAuth2MobileCodeAuthenticateDTO;
|
||||||
import cn.iocoder.mall.system.biz.dto.oatuh2.OAuth2UsernameAuthenticateDTO;
|
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.account.AccountService;
|
||||||
|
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.oauth2.OAuth2Service;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.beans.factory.annotation.Value;
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
@ -39,6 +43,8 @@ public class OAuth2ServiceImpl implements OAuth2Service {
|
|||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private AccountService accountService;
|
private AccountService accountService;
|
||||||
|
@Autowired
|
||||||
|
private OAuth2MobileCodeService oauth2MobileCodeService;
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private OAuth2AccessTokenMapper oauth2AccessTokenMapper;
|
private OAuth2AccessTokenMapper oauth2AccessTokenMapper;
|
||||||
@ -47,16 +53,17 @@ public class OAuth2ServiceImpl implements OAuth2Service {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
@Transactional
|
@Transactional
|
||||||
public OAuth2AccessTokenBO authenticate(OAuth2UsernameAuthenticateDTO usernameAuthenticateDTO) {
|
public OAuth2AccessTokenBO authenticate(OAuth2UsernameAuthenticateDTO authenticateDTO) {
|
||||||
// 获得账号
|
// 获得账号
|
||||||
AccountBO accountBO = accountService.getByUsername(usernameAuthenticateDTO.getUsername());
|
AccountBO accountBO = accountService.getByUsername(authenticateDTO.getUsername());
|
||||||
if (accountBO == null) {
|
if (accountBO == null) {
|
||||||
throw ServiceExceptionUtil.exception(OAUTH2_ACCOUNT_NOT_FOUND);
|
throw ServiceExceptionUtil.exception(OAUTH2_ACCOUNT_NOT_FOUND);
|
||||||
}
|
}
|
||||||
// 校验密码
|
// 校验密码
|
||||||
if (!accountService.matchPassword(usernameAuthenticateDTO.getPassword(), accountBO.getPassword())) {
|
if (!accountService.matchPassword(authenticateDTO.getPassword(), accountBO.getPassword())) {
|
||||||
throw ServiceExceptionUtil.exception(OAUTH2_ACCOUNT_PASSWORD_ERROR);
|
throw ServiceExceptionUtil.exception(OAUTH2_ACCOUNT_PASSWORD_ERROR);
|
||||||
}
|
}
|
||||||
|
// TODO 记录账号最后登陆时间和 ip 等
|
||||||
// 创建刷新令牌 + 访问令牌
|
// 创建刷新令牌 + 访问令牌
|
||||||
OAuth2RefreshTokenDO oauth2RefreshTokenDO = createOAuth2RefreshToken(accountBO.getId());
|
OAuth2RefreshTokenDO oauth2RefreshTokenDO = createOAuth2RefreshToken(accountBO.getId());
|
||||||
OAuth2AccessTokenDO oauth2AccessTokenDO = createOAuth2AccessToken(accountBO.getId(), oauth2RefreshTokenDO.getId());
|
OAuth2AccessTokenDO oauth2AccessTokenDO = createOAuth2AccessToken(accountBO.getId(), oauth2RefreshTokenDO.getId());
|
||||||
@ -65,8 +72,29 @@ public class OAuth2ServiceImpl implements OAuth2Service {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public OAuth2AccessTokenBO authenticate(OAuth2MobileCodeAuthenticateDTO mobileCodeAuthenticateDTO) {
|
@Transactional
|
||||||
return null;
|
public OAuth2AccessTokenBO authenticate(OAuth2MobileCodeAuthenticateDTO authenticateDTO) {
|
||||||
|
// 校验手机格式
|
||||||
|
if (!ValidationUtil.isMobile(authenticateDTO.getMobile())) {
|
||||||
|
throw ServiceExceptionUtil.exception(SysErrorCodeEnum.VALIDATION_REQUEST_PARAM_ERROR.getCode(), "手机格式不正确"); // TODO 有点搓
|
||||||
|
}
|
||||||
|
// 使用手机验证码。如果验证不通过,则会抛出异常
|
||||||
|
oauth2MobileCodeService.use(authenticateDTO.getMobile(), authenticateDTO.getCode());
|
||||||
|
// 获得账号
|
||||||
|
AccountBO accountBO = accountService.getByMobile(authenticateDTO.getMobile());
|
||||||
|
if (accountBO == null) { // 账号不存时,自动创建
|
||||||
|
// 创建账号
|
||||||
|
accountBO = accountService.create(new AccountCreateDTO()
|
||||||
|
.setMobile(authenticateDTO.getMobile())
|
||||||
|
.setCreateIp(authenticateDTO.getIp())
|
||||||
|
);
|
||||||
|
}
|
||||||
|
// TODO 记录账号最后登陆时间和 ip 等
|
||||||
|
// 创建刷新令牌 + 访问令牌
|
||||||
|
OAuth2RefreshTokenDO oauth2RefreshTokenDO = createOAuth2RefreshToken(accountBO.getId());
|
||||||
|
OAuth2AccessTokenDO oauth2AccessTokenDO = createOAuth2AccessToken(accountBO.getId(), oauth2RefreshTokenDO.getId());
|
||||||
|
// 返回访问令牌
|
||||||
|
return OAuth2Convert.INSTANCE.convert(oauth2AccessTokenDO);
|
||||||
}
|
}
|
||||||
|
|
||||||
private OAuth2AccessTokenDO createOAuth2AccessToken(Integer accountId, String refreshToken) {
|
private OAuth2AccessTokenDO createOAuth2AccessToken(Integer accountId, String refreshToken) {
|
||||||
|
@ -1,10 +1,13 @@
|
|||||||
package cn.iocoder.mall.system.biz.service.user;
|
package cn.iocoder.mall.system.biz.service.user;
|
||||||
|
|
||||||
|
import cn.iocoder.mall.system.biz.bo.user.UserAuthenticateBO;
|
||||||
|
import cn.iocoder.mall.system.biz.dto.oatuh2.OAuth2MobileCodeAuthenticateDTO;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 用户 Service 接口
|
* 用户 Service 接口
|
||||||
*/
|
*/
|
||||||
public interface UserService {
|
public interface UserService {
|
||||||
|
|
||||||
|
UserAuthenticateBO authenticate(OAuth2MobileCodeAuthenticateDTO authenticateDTO);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1,8 +1,47 @@
|
|||||||
package cn.iocoder.mall.system.biz.service.user.impl;
|
package cn.iocoder.mall.system.biz.service.user.impl;
|
||||||
|
|
||||||
|
import cn.iocoder.mall.system.biz.bo.ouath2.OAuth2AccessTokenBO;
|
||||||
|
import cn.iocoder.mall.system.biz.bo.user.UserAuthenticateBO;
|
||||||
|
import cn.iocoder.mall.system.biz.bo.user.UserBO;
|
||||||
|
import cn.iocoder.mall.system.biz.convert.UserConvert;
|
||||||
|
import cn.iocoder.mall.system.biz.dao.user.UserMapper;
|
||||||
|
import cn.iocoder.mall.system.biz.dataobject.user.UserDO;
|
||||||
|
import cn.iocoder.mall.system.biz.dto.oatuh2.OAuth2MobileCodeAuthenticateDTO;
|
||||||
|
import cn.iocoder.mall.system.biz.service.oauth2.OAuth2Service;
|
||||||
import cn.iocoder.mall.system.biz.service.user.UserService;
|
import cn.iocoder.mall.system.biz.service.user.UserService;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
|
||||||
@Service
|
@Service
|
||||||
public class UserServiceImpl implements UserService {
|
public class UserServiceImpl implements UserService {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private UserMapper userMapper;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private OAuth2Service oAuth2Service;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Transactional
|
||||||
|
public UserAuthenticateBO authenticate(OAuth2MobileCodeAuthenticateDTO authenticateDTO) {
|
||||||
|
// 执行认证
|
||||||
|
OAuth2AccessTokenBO accessTokenBO = oAuth2Service.authenticate(authenticateDTO);
|
||||||
|
// 获得用户
|
||||||
|
UserDO userDO = userMapper.selectById(accessTokenBO.getAccountId());
|
||||||
|
if (userDO == null) {
|
||||||
|
userDO = this.creatUser(accessTokenBO.getAccountId());
|
||||||
|
}
|
||||||
|
UserBO userBO = UserConvert.INSTANCE.convert(userDO);
|
||||||
|
// 拼装返回
|
||||||
|
return UserConvert.INSTANCE.convert(userBO, accessTokenBO);
|
||||||
|
}
|
||||||
|
|
||||||
|
private UserDO creatUser(Integer accountId) {
|
||||||
|
UserDO user = new UserDO();
|
||||||
|
user.setAccountId(accountId);
|
||||||
|
userMapper.insert(user);
|
||||||
|
return user;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -10,7 +10,7 @@ import cn.iocoder.mall.system.biz.service.admin.AdminService;
|
|||||||
import cn.iocoder.mall.system.biz.service.oauth2.OAuth2Service;
|
import cn.iocoder.mall.system.biz.service.oauth2.OAuth2Service;
|
||||||
import cn.iocoder.mall.system.rest.convert.oauth2.AdminsOAuth2Convert;
|
import cn.iocoder.mall.system.rest.convert.oauth2.AdminsOAuth2Convert;
|
||||||
import cn.iocoder.mall.system.rest.request.oauth2.AdminsOAuth2UsernameAuthenticateRequest;
|
import cn.iocoder.mall.system.rest.request.oauth2.AdminsOAuth2UsernameAuthenticateRequest;
|
||||||
import cn.iocoder.mall.system.rest.response.AdminsAuthorizeUsernameLoginResponse;
|
import cn.iocoder.mall.system.rest.response.oauth2.AdminsOAuth2AuthenticateResponse;
|
||||||
import io.swagger.annotations.Api;
|
import io.swagger.annotations.Api;
|
||||||
import io.swagger.annotations.ApiOperation;
|
import io.swagger.annotations.ApiOperation;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
@ -32,10 +32,10 @@ public class AdminsOAuth2Controller {
|
|||||||
|
|
||||||
@PostMapping("/username_authenticate")
|
@PostMapping("/username_authenticate")
|
||||||
@ApiOperation("用户名认证")
|
@ApiOperation("用户名认证")
|
||||||
public CommonResult<AdminsAuthorizeUsernameLoginResponse> usernameAuthenticate(AdminsOAuth2UsernameAuthenticateRequest request) {
|
public CommonResult<AdminsOAuth2AuthenticateResponse> usernameAuthenticate(AdminsOAuth2UsernameAuthenticateRequest request) {
|
||||||
// 执行认证
|
// 执行认证
|
||||||
OAuth2UsernameAuthenticateDTO usernameAuthenticateDTO = AdminsOAuth2Convert.INSTANCE.convert(request);
|
OAuth2UsernameAuthenticateDTO authenticateDTO = AdminsOAuth2Convert.INSTANCE.convert(request);
|
||||||
OAuth2AccessTokenBO accessTokenBO = oauth2Service.authenticate(usernameAuthenticateDTO);
|
OAuth2AccessTokenBO accessTokenBO = oauth2Service.authenticate(authenticateDTO);
|
||||||
// 获得 Admin 信息
|
// 获得 Admin 信息
|
||||||
AdminBO adminBO = adminService.get(accessTokenBO.getAccountId());
|
AdminBO adminBO = adminService.get(accessTokenBO.getAccountId());
|
||||||
if (adminBO == null) {
|
if (adminBO == null) {
|
||||||
|
@ -3,10 +3,15 @@ package cn.iocoder.mall.system.rest.controller.users;
|
|||||||
import cn.iocoder.common.framework.constant.MallConstants;
|
import cn.iocoder.common.framework.constant.MallConstants;
|
||||||
import cn.iocoder.common.framework.util.HttpUtil;
|
import cn.iocoder.common.framework.util.HttpUtil;
|
||||||
import cn.iocoder.common.framework.vo.CommonResult;
|
import cn.iocoder.common.framework.vo.CommonResult;
|
||||||
|
import cn.iocoder.mall.system.biz.bo.user.UserAuthenticateBO;
|
||||||
|
import cn.iocoder.mall.system.biz.dto.oatuh2.OAuth2MobileCodeAuthenticateDTO;
|
||||||
import cn.iocoder.mall.system.biz.dto.oatuh2.OAuth2MobileCodeSendDTO;
|
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.OAuth2MobileCodeService;
|
||||||
import cn.iocoder.mall.system.biz.service.oauth2.OAuth2Service;
|
import cn.iocoder.mall.system.biz.service.oauth2.OAuth2Service;
|
||||||
import cn.iocoder.mall.system.biz.service.user.UserService;
|
import cn.iocoder.mall.system.biz.service.user.UserService;
|
||||||
|
import cn.iocoder.mall.system.rest.convert.oauth2.UsersOAuth2Convert;
|
||||||
|
import cn.iocoder.mall.system.rest.request.oauth2.UsersOAuth2MobileCodeAuthenticateRequest;
|
||||||
|
import cn.iocoder.mall.system.rest.response.user.UsersOAuth2AuthenticateResponse;
|
||||||
import io.swagger.annotations.Api;
|
import io.swagger.annotations.Api;
|
||||||
import io.swagger.annotations.ApiImplicitParam;
|
import io.swagger.annotations.ApiImplicitParam;
|
||||||
import io.swagger.annotations.ApiOperation;
|
import io.swagger.annotations.ApiOperation;
|
||||||
@ -30,6 +35,20 @@ public class UsersOAuth2Controller {
|
|||||||
@Autowired
|
@Autowired
|
||||||
private OAuth2MobileCodeService oauth2MobileCodeService;
|
private OAuth2MobileCodeService oauth2MobileCodeService;
|
||||||
|
|
||||||
|
@PostMapping("/mobile_code_authenticate")
|
||||||
|
@ApiOperation("手机验证码认证")
|
||||||
|
public CommonResult<UsersOAuth2AuthenticateResponse> mobileCodeAuthenticate(UsersOAuth2MobileCodeAuthenticateRequest request,
|
||||||
|
HttpServletRequest httpRequest) {
|
||||||
|
// 执行认证
|
||||||
|
OAuth2MobileCodeAuthenticateDTO authenticateDTO = UsersOAuth2Convert.INSTANCE.convert(request)
|
||||||
|
.setIp(HttpUtil.getIp(httpRequest));
|
||||||
|
UserAuthenticateBO userAuthenticateBO = userService.authenticate(authenticateDTO);
|
||||||
|
// 转换返回
|
||||||
|
return CommonResult.success(
|
||||||
|
UsersOAuth2Convert.INSTANCE.convert(userAuthenticateBO)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
@PostMapping("/send_mobile_code")
|
@PostMapping("/send_mobile_code")
|
||||||
@ApiOperation("发送手机验证码")
|
@ApiOperation("发送手机验证码")
|
||||||
@ApiImplicitParam(name = "mobile", value = "手机号", required = true, example = "15601691234")
|
@ApiImplicitParam(name = "mobile", value = "手机号", required = true, example = "15601691234")
|
||||||
@ -38,7 +57,7 @@ public class UsersOAuth2Controller {
|
|||||||
// 执行发送验证码
|
// 执行发送验证码
|
||||||
OAuth2MobileCodeSendDTO sendDTO = new OAuth2MobileCodeSendDTO()
|
OAuth2MobileCodeSendDTO sendDTO = new OAuth2MobileCodeSendDTO()
|
||||||
.setMobile(mobile).setIp(HttpUtil.getIp(request));
|
.setMobile(mobile).setIp(HttpUtil.getIp(request));
|
||||||
oauth2MobileCodeService.sendMobileCode(sendDTO);
|
oauth2MobileCodeService.send(sendDTO);
|
||||||
// 返回成功
|
// 返回成功
|
||||||
return CommonResult.success(true);
|
return CommonResult.success(true);
|
||||||
}
|
}
|
||||||
|
@ -4,10 +4,9 @@ import cn.iocoder.mall.system.biz.bo.admin.AdminBO;
|
|||||||
import cn.iocoder.mall.system.biz.bo.ouath2.OAuth2AccessTokenBO;
|
import cn.iocoder.mall.system.biz.bo.ouath2.OAuth2AccessTokenBO;
|
||||||
import cn.iocoder.mall.system.biz.dto.oatuh2.OAuth2UsernameAuthenticateDTO;
|
import cn.iocoder.mall.system.biz.dto.oatuh2.OAuth2UsernameAuthenticateDTO;
|
||||||
import cn.iocoder.mall.system.rest.request.oauth2.AdminsOAuth2UsernameAuthenticateRequest;
|
import cn.iocoder.mall.system.rest.request.oauth2.AdminsOAuth2UsernameAuthenticateRequest;
|
||||||
import cn.iocoder.mall.system.rest.response.AdminsAuthorizeUsernameLoginResponse;
|
import cn.iocoder.mall.system.rest.response.oauth2.AdminsOAuth2AuthenticateResponse;
|
||||||
import org.mapstruct.Mapper;
|
import org.mapstruct.Mapper;
|
||||||
import org.mapstruct.Mapping;
|
import org.mapstruct.Mapping;
|
||||||
import org.mapstruct.Mappings;
|
|
||||||
import org.mapstruct.factory.Mappers;
|
import org.mapstruct.factory.Mappers;
|
||||||
|
|
||||||
@Mapper
|
@Mapper
|
||||||
@ -17,13 +16,10 @@ public interface AdminsOAuth2Convert {
|
|||||||
|
|
||||||
OAuth2UsernameAuthenticateDTO convert(AdminsOAuth2UsernameAuthenticateRequest request);
|
OAuth2UsernameAuthenticateDTO convert(AdminsOAuth2UsernameAuthenticateRequest request);
|
||||||
|
|
||||||
@Mappings(value = {
|
@Mapping(source = "adminBO", target = "admin")
|
||||||
@Mapping(source = "adminBO.id", target = "id"),
|
@Mapping(source = "accessTokenBO.id", target = "token.accessToken")
|
||||||
@Mapping(source = "adminBO.name", target = "name"),
|
@Mapping(source = "accessTokenBO.refreshToken", target = "token.refreshToken")
|
||||||
@Mapping(source = "accessTokenBO.id", target = "token.accessToken"),
|
@Mapping(source = "accessTokenBO.expiresTime", target = "token.expiresTime")
|
||||||
@Mapping(source = "accessTokenBO.refreshToken", target = "token.refreshToken"),
|
AdminsOAuth2AuthenticateResponse convert(AdminBO adminBO, OAuth2AccessTokenBO accessTokenBO);
|
||||||
@Mapping(source = "accessTokenBO.expiresTime", target = "token.expiresTime"),
|
|
||||||
})
|
|
||||||
AdminsAuthorizeUsernameLoginResponse convert(AdminBO adminBO, OAuth2AccessTokenBO accessTokenBO);
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,21 @@
|
|||||||
|
package cn.iocoder.mall.system.rest.convert.oauth2;
|
||||||
|
|
||||||
|
import cn.iocoder.mall.system.biz.bo.user.UserAuthenticateBO;
|
||||||
|
import cn.iocoder.mall.system.biz.dto.oatuh2.OAuth2MobileCodeAuthenticateDTO;
|
||||||
|
import cn.iocoder.mall.system.rest.request.oauth2.UsersOAuth2MobileCodeAuthenticateRequest;
|
||||||
|
import cn.iocoder.mall.system.rest.response.user.UsersOAuth2AuthenticateResponse;
|
||||||
|
import org.mapstruct.Mapper;
|
||||||
|
import org.mapstruct.Mapping;
|
||||||
|
import org.mapstruct.factory.Mappers;
|
||||||
|
|
||||||
|
@Mapper
|
||||||
|
public interface UsersOAuth2Convert {
|
||||||
|
|
||||||
|
UsersOAuth2Convert INSTANCE = Mappers.getMapper(UsersOAuth2Convert.class);
|
||||||
|
|
||||||
|
OAuth2MobileCodeAuthenticateDTO convert(UsersOAuth2MobileCodeAuthenticateRequest request);
|
||||||
|
|
||||||
|
@Mapping(source = "token.id", target = "token.accessToken")
|
||||||
|
UsersOAuth2AuthenticateResponse convert(UserAuthenticateBO userAuthenticateBO);
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,7 @@
|
|||||||
|
package cn.iocoder.mall.system.rest.convert.user;
|
||||||
|
|
||||||
|
import org.mapstruct.Mapper;
|
||||||
|
|
||||||
|
@Mapper
|
||||||
|
public interface UsersUserConvert {
|
||||||
|
}
|
@ -0,0 +1,29 @@
|
|||||||
|
package cn.iocoder.mall.system.rest.request.oauth2;
|
||||||
|
|
||||||
|
import io.swagger.annotations.ApiModel;
|
||||||
|
import io.swagger.annotations.ApiModelProperty;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.experimental.Accessors;
|
||||||
|
import org.hibernate.validator.constraints.Length;
|
||||||
|
|
||||||
|
import javax.validation.constraints.NotEmpty;
|
||||||
|
import javax.validation.constraints.Pattern;
|
||||||
|
|
||||||
|
@ApiModel("用户 - OAuth2 模块 - 手机验证码认证请求")
|
||||||
|
@Data
|
||||||
|
@Accessors(chain = true)
|
||||||
|
public class UsersOAuth2MobileCodeAuthenticateRequest {
|
||||||
|
|
||||||
|
@ApiModelProperty(value = "手机号", required = true, example = "15601691300")
|
||||||
|
@NotEmpty(message = "手机号不能为空")
|
||||||
|
@Length(min = 11, max = 11, message = "账号长度为 11 位")
|
||||||
|
@Pattern(regexp = "^[0-9]+$", message = "手机号必须都是数字")
|
||||||
|
private String mobile;
|
||||||
|
|
||||||
|
@ApiModelProperty(value = "手机验证码", required = true, example = "1024")
|
||||||
|
@NotEmpty(message = "手机验证码不能为空")
|
||||||
|
@Length(min = 4, max = 6, message = "手机验证码长度为 4-6 位")
|
||||||
|
@Pattern(regexp = "^[0-9]+$", message = "手机验证码必须都是数字")
|
||||||
|
private String code;
|
||||||
|
|
||||||
|
}
|
@ -1 +0,0 @@
|
|||||||
package cn.iocoder.mall.system.rest.request;
|
|
@ -0,0 +1,49 @@
|
|||||||
|
package cn.iocoder.mall.system.rest.response.oauth2;
|
||||||
|
|
||||||
|
import io.swagger.annotations.ApiModel;
|
||||||
|
import io.swagger.annotations.ApiModelProperty;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.experimental.Accessors;
|
||||||
|
|
||||||
|
import java.util.Date;
|
||||||
|
|
||||||
|
@ApiModel("管理员 - OAuth2 模块 - 认证响应")
|
||||||
|
@Data
|
||||||
|
@Accessors(chain = true)
|
||||||
|
public class AdminsOAuth2AuthenticateResponse {
|
||||||
|
|
||||||
|
@Data
|
||||||
|
public static class Token {
|
||||||
|
|
||||||
|
@ApiModelProperty(value = "access token", required = true, example = "001e8f49b20e47f7b3a2de774497cd50")
|
||||||
|
private String accessToken;
|
||||||
|
|
||||||
|
@ApiModelProperty(value = "refresh token", required = true, example = "001e8f49b20e47f7b3a2de774497cd50")
|
||||||
|
private String refreshToken;
|
||||||
|
|
||||||
|
@ApiModelProperty(value = "过期时间", required = true)
|
||||||
|
private Date expiresTime;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Data
|
||||||
|
public static class Admin {
|
||||||
|
|
||||||
|
@ApiModelProperty(value = "管理员编号", required = true, example = "1")
|
||||||
|
private Integer id;
|
||||||
|
|
||||||
|
@ApiModelProperty(value = "真实名字", required = true, example = "小王")
|
||||||
|
private String name;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* TODO 晚点测试下 swagger 的表现
|
||||||
|
*/
|
||||||
|
private Admin admin;
|
||||||
|
/**
|
||||||
|
* TODO 晚点测试下 swagger 的表现
|
||||||
|
*/
|
||||||
|
private Token token;
|
||||||
|
|
||||||
|
}
|
@ -1,4 +1,4 @@
|
|||||||
package cn.iocoder.mall.system.rest.response;
|
package cn.iocoder.mall.system.rest.response.user;
|
||||||
|
|
||||||
import io.swagger.annotations.ApiModel;
|
import io.swagger.annotations.ApiModel;
|
||||||
import io.swagger.annotations.ApiModelProperty;
|
import io.swagger.annotations.ApiModelProperty;
|
||||||
@ -7,10 +7,10 @@ import lombok.experimental.Accessors;
|
|||||||
|
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
|
|
||||||
@ApiModel("管理员 - 认证 - 用户名登陆响应")
|
@ApiModel("用户 - OAuth2 模块 - 认证响应")
|
||||||
@Data
|
@Data
|
||||||
@Accessors(chain = true)
|
@Accessors(chain = true)
|
||||||
public class AdminsAuthorizeUsernameLoginResponse {
|
public class UsersOAuth2AuthenticateResponse {
|
||||||
|
|
||||||
@Data
|
@Data
|
||||||
public static class Token {
|
public static class Token {
|
||||||
@ -26,11 +26,21 @@ public class AdminsAuthorizeUsernameLoginResponse {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Data
|
||||||
|
public static class User {
|
||||||
|
|
||||||
@ApiModelProperty(value = "管理员编号", required = true, example = "1")
|
@ApiModelProperty(value = "管理员编号", required = true, example = "1")
|
||||||
private Integer id;
|
private Integer id;
|
||||||
|
|
||||||
@ApiModelProperty(value = "真实名字", required = true, example = "小王")
|
@ApiModelProperty(value = "昵称", required = true, example = "小王")
|
||||||
private String name;
|
private String nickname;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* TODO 晚点测试下 swagger 的表现
|
||||||
|
*/
|
||||||
|
private User user;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* TODO 晚点测试下 swagger 的表现
|
* TODO 晚点测试下 swagger 的表现
|
@ -5,13 +5,8 @@ import cn.iocoder.common.framework.vo.CommonResult;
|
|||||||
import cn.iocoder.mall.system.api.OAuth2Service;
|
import cn.iocoder.mall.system.api.OAuth2Service;
|
||||||
import cn.iocoder.mall.system.api.bo.oauth2.OAuth2AccessTokenBO;
|
import cn.iocoder.mall.system.api.bo.oauth2.OAuth2AccessTokenBO;
|
||||||
import cn.iocoder.mall.system.api.dto.oauth2.OAuth2RefreshTokenDTO;
|
import cn.iocoder.mall.system.api.dto.oauth2.OAuth2RefreshTokenDTO;
|
||||||
import cn.iocoder.mall.user.api.MobileCodeService;
|
|
||||||
import cn.iocoder.mall.user.api.UserService;
|
import cn.iocoder.mall.user.api.UserService;
|
||||||
import cn.iocoder.mall.user.api.bo.user.UserAuthenticationBO;
|
|
||||||
import cn.iocoder.mall.user.api.dto.user.UserAuthenticationByMobileCodeDTO;
|
|
||||||
import io.swagger.annotations.Api;
|
import io.swagger.annotations.Api;
|
||||||
import io.swagger.annotations.ApiImplicitParam;
|
|
||||||
import io.swagger.annotations.ApiOperation;
|
|
||||||
import org.apache.dubbo.config.annotation.Reference;
|
import org.apache.dubbo.config.annotation.Reference;
|
||||||
import org.springframework.web.bind.annotation.PostMapping;
|
import org.springframework.web.bind.annotation.PostMapping;
|
||||||
import org.springframework.web.bind.annotation.RequestMapping;
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
@ -29,8 +24,6 @@ public class PassportController {
|
|||||||
private OAuth2Service oauth2Service;
|
private OAuth2Service oauth2Service;
|
||||||
@Reference(validation = "true", version = "${dubbo.provider.UserService.version}")
|
@Reference(validation = "true", version = "${dubbo.provider.UserService.version}")
|
||||||
private UserService userService;
|
private UserService userService;
|
||||||
@Reference(validation = "true", version = "${dubbo.provider.MobileCodeService.version}")
|
|
||||||
private MobileCodeService mobileCodeService;
|
|
||||||
|
|
||||||
// TODO 功能:手机密码登陆
|
// TODO 功能:手机密码登陆
|
||||||
// @PostMapping("/mobile/pwd/login")
|
// @PostMapping("/mobile/pwd/login")
|
||||||
@ -39,20 +32,6 @@ public class PassportController {
|
|||||||
// return oauth2Service.getAccessToken(clientId, clientSecret, mobile, password);
|
// return oauth2Service.getAccessToken(clientId, clientSecret, mobile, password);
|
||||||
// }
|
// }
|
||||||
|
|
||||||
@PostMapping("/mobile/register")
|
|
||||||
@ApiOperation(value = "手机号 + 验证码登陆(注册)", notes = "如果手机对应的账号不存在,则会自动创建")
|
|
||||||
public CommonResult<UserAuthenticationBO> mobileRegister(UserAuthenticationByMobileCodeDTO userAuthenticationByMobileCodeDTO) {
|
|
||||||
return success(userService.authenticationByMobileCode(userAuthenticationByMobileCodeDTO));
|
|
||||||
}
|
|
||||||
|
|
||||||
@PostMapping("mobile/send_register_code")
|
|
||||||
@ApiOperation(value = "发送手机验证码")
|
|
||||||
@ApiImplicitParam(name = "mobile", value = "手机号", required = true, example = "15601691300")
|
|
||||||
public CommonResult<Boolean> mobileSend(@RequestParam("mobile") String mobile) {
|
|
||||||
mobileCodeService.send(mobile);
|
|
||||||
return success(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO 芋艿,改绑手机号
|
// TODO 芋艿,改绑手机号
|
||||||
|
|
||||||
// TODO 功能:qq 登陆
|
// TODO 功能:qq 登陆
|
||||||
|
@ -1,14 +0,0 @@
|
|||||||
package cn.iocoder.mall.user.api;
|
|
||||||
|
|
||||||
import cn.iocoder.common.framework.exception.ServiceException;
|
|
||||||
|
|
||||||
public interface MobileCodeService {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 发送验证码
|
|
||||||
*
|
|
||||||
* @param mobile 手机号
|
|
||||||
*/
|
|
||||||
void send(String mobile) throws ServiceException;
|
|
||||||
|
|
||||||
}
|
|
@ -2,17 +2,13 @@ package cn.iocoder.mall.user.api;
|
|||||||
|
|
||||||
import cn.iocoder.common.framework.constant.CommonStatusEnum;
|
import cn.iocoder.common.framework.constant.CommonStatusEnum;
|
||||||
import cn.iocoder.common.framework.validator.InEnum;
|
import cn.iocoder.common.framework.validator.InEnum;
|
||||||
import cn.iocoder.mall.user.api.bo.user.UserAuthenticationBO;
|
|
||||||
import cn.iocoder.mall.user.api.bo.UserBO;
|
import cn.iocoder.mall.user.api.bo.UserBO;
|
||||||
import cn.iocoder.mall.user.api.bo.UserPageBO;
|
import cn.iocoder.mall.user.api.bo.UserPageBO;
|
||||||
import cn.iocoder.mall.user.api.dto.UserPageDTO;
|
import cn.iocoder.mall.user.api.dto.UserPageDTO;
|
||||||
import cn.iocoder.mall.user.api.dto.UserUpdateDTO;
|
import cn.iocoder.mall.user.api.dto.UserUpdateDTO;
|
||||||
import cn.iocoder.mall.user.api.dto.user.UserAuthenticationByMobileCodeDTO;
|
|
||||||
|
|
||||||
public interface UserService {
|
public interface UserService {
|
||||||
|
|
||||||
UserAuthenticationBO authenticationByMobileCode(UserAuthenticationByMobileCodeDTO userAuthenticationByMobileCodeDTO);
|
|
||||||
|
|
||||||
UserPageBO getUserPage(UserPageDTO userPageDTO);
|
UserPageBO getUserPage(UserPageDTO userPageDTO);
|
||||||
|
|
||||||
UserBO getUser(Integer userId);
|
UserBO getUser(Integer userId);
|
||||||
|
@ -10,6 +10,7 @@ import java.util.Date;
|
|||||||
*/
|
*/
|
||||||
@Data
|
@Data
|
||||||
@Accessors(chain = true)
|
@Accessors(chain = true)
|
||||||
|
@Deprecated
|
||||||
public class UserRegisterDO {
|
public class UserRegisterDO {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1,80 +0,0 @@
|
|||||||
package cn.iocoder.mall.user.biz.service;
|
|
||||||
|
|
||||||
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.user.api.MobileCodeService;
|
|
||||||
import cn.iocoder.mall.user.api.constant.UserErrorCodeEnum;
|
|
||||||
import cn.iocoder.mall.user.biz.dao.MobileCodeMapper;
|
|
||||||
import cn.iocoder.mall.user.biz.dataobject.MobileCodeDO;
|
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
|
||||||
import org.springframework.beans.factory.annotation.Value;
|
|
||||||
import org.springframework.stereotype.Service;
|
|
||||||
|
|
||||||
import java.util.Date;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* MobileCodeService ,实现用户登陆时需要的验证码
|
|
||||||
*/
|
|
||||||
@Service
|
|
||||||
@org.apache.dubbo.config.annotation.Service(validation = "true", version = "${dubbo.provider.MobileCodeService.version}")
|
|
||||||
public class MobileCodeServiceImpl implements MobileCodeService {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 每条验证码的过期时间,单位:毫秒
|
|
||||||
*/
|
|
||||||
@Value("${modules.mobile-code-service.code-expire-time-millis}")
|
|
||||||
private int codeExpireTimes;
|
|
||||||
/**
|
|
||||||
* 每日发送最大数量
|
|
||||||
*/
|
|
||||||
@Value("${modules.mobile-code-service.send-maximum-quantity-per-day}")
|
|
||||||
private int sendMaximumQuantityPerDay;
|
|
||||||
/**
|
|
||||||
* 短信发送频率,单位:毫秒
|
|
||||||
*/
|
|
||||||
@Value("${modules.mobile-code-service.send-frequency}")
|
|
||||||
private int sendFrequency;
|
|
||||||
|
|
||||||
@Autowired
|
|
||||||
private MobileCodeMapper mobileCodeMapper;
|
|
||||||
@Autowired
|
|
||||||
private UserServiceImpl userService;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 校验手机号的最后一个手机验证码是否有效
|
|
||||||
*
|
|
||||||
* @param mobile 手机号
|
|
||||||
* @param code 验证码
|
|
||||||
* @return 手机验证码信息
|
|
||||||
*/
|
|
||||||
public MobileCodeDO validLastMobileCode(String mobile, String code) {
|
|
||||||
// return new MobileCodeDO().setCode(code).setCreateTime(new Date()).setId(1);
|
|
||||||
MobileCodeDO mobileCodePO = mobileCodeMapper.selectLast1ByMobile(mobile);
|
|
||||||
if (mobileCodePO == null) { // 若验证码不存在,抛出异常
|
|
||||||
throw ServiceExceptionUtil.exception(UserErrorCodeEnum.MOBILE_CODE_NOT_FOUND.getCode());
|
|
||||||
}
|
|
||||||
if (System.currentTimeMillis() - mobileCodePO.getCreateTime().getTime() >= codeExpireTimes) { // 验证码已过期
|
|
||||||
throw ServiceExceptionUtil.exception(UserErrorCodeEnum.MOBILE_CODE_EXPIRED.getCode());
|
|
||||||
}
|
|
||||||
if (mobileCodePO.getUsed()) { // 验证码已使用
|
|
||||||
throw ServiceExceptionUtil.exception(UserErrorCodeEnum.MOBILE_CODE_USED.getCode());
|
|
||||||
}
|
|
||||||
if (!mobileCodePO.getCode().equals(code)) {
|
|
||||||
throw ServiceExceptionUtil.exception(UserErrorCodeEnum.MOBILE_CODE_NOT_CORRECT.getCode());
|
|
||||||
}
|
|
||||||
return mobileCodePO;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 更新手机验证码已使用
|
|
||||||
*
|
|
||||||
* @param id 验证码编号
|
|
||||||
* @param userId 用户编号
|
|
||||||
*/
|
|
||||||
public void useMobileCode(Integer id, Integer userId) {
|
|
||||||
MobileCodeDO update = new MobileCodeDO().setId(id).setUsed(true).setUsedUserId(userId).setUsedTime(new Date());
|
|
||||||
mobileCodeMapper.updateById(update);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -43,8 +43,6 @@ public class UserServiceImpl implements UserService {
|
|||||||
private UserMapper userMapper;
|
private UserMapper userMapper;
|
||||||
@Autowired
|
@Autowired
|
||||||
private UserRegisterMapper userRegisterMapper;
|
private UserRegisterMapper userRegisterMapper;
|
||||||
@Autowired
|
|
||||||
private MobileCodeServiceImpl mobileCodeService;
|
|
||||||
|
|
||||||
@Reference(validation = "true", version = "${dubbo.consumer.OAuth2Service.version}")
|
@Reference(validation = "true", version = "${dubbo.consumer.OAuth2Service.version}")
|
||||||
private OAuth2Service oAuth2Service;
|
private OAuth2Service oAuth2Service;
|
||||||
@ -79,36 +77,6 @@ public class UserServiceImpl implements UserService {
|
|||||||
userRegisterMapper.insert(userRegisterDO);
|
userRegisterMapper.insert(userRegisterDO);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
@Transactional
|
|
||||||
public UserAuthenticationBO authenticationByMobileCode(UserAuthenticationByMobileCodeDTO userAuthenticationByMobileCodeDTO) {
|
|
||||||
String mobile = userAuthenticationByMobileCodeDTO.getMobile();
|
|
||||||
String code = userAuthenticationByMobileCodeDTO.getCode();
|
|
||||||
// 校验手机格式
|
|
||||||
if (!ValidationUtil.isMobile(mobile)) {
|
|
||||||
throw ServiceExceptionUtil.exception(SysErrorCodeEnum.VALIDATION_REQUEST_PARAM_ERROR.getCode(), "手机格式不正确"); // TODO 有点搓
|
|
||||||
}
|
|
||||||
// 校验验证码是否正确
|
|
||||||
MobileCodeDO mobileCodeDO = mobileCodeService.validLastMobileCode(mobile, code);
|
|
||||||
// 获得用户
|
|
||||||
UserDO user = userMapper.selectByMobile(mobile);
|
|
||||||
if (user == null) { // 用户不存在,则进行创建
|
|
||||||
user = new UserDO().setMobile(mobile).setStatus(UserConstants.STATUS_ENABLE);
|
|
||||||
user.setCreateTime(new Date());
|
|
||||||
user.setDeleted(DeletedStatusEnum.DELETED_NO.getValue());
|
|
||||||
userMapper.insert(user);
|
|
||||||
// 插入注册信息 TODO 芋艿 后续完善,记录 ip、ua 等等
|
|
||||||
createUserRegister(user);
|
|
||||||
}
|
|
||||||
// 更新验证码已使用
|
|
||||||
mobileCodeService.useMobileCode(mobileCodeDO.getId(), user.getId());
|
|
||||||
// 创建 accessToken
|
|
||||||
OAuth2AccessTokenBO accessTokenBO = oAuth2Service.createToken(new OAuth2CreateTokenDTO().setUserId(user.getId())
|
|
||||||
.setUserType(UserTypeEnum.USER.getValue()));
|
|
||||||
// 转换返回
|
|
||||||
return UserConvert.INSTANCE.convert2(user).setToken(accessTokenBO);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public UserPageBO getUserPage(UserPageDTO userPageDTO) {
|
public UserPageBO getUserPage(UserPageDTO userPageDTO) {
|
||||||
UserPageBO userPageBO = new UserPageBO();
|
UserPageBO userPageBO = new UserPageBO();
|
||||||
|
Loading…
Reference in New Issue
Block a user