- 后端:User 模块,接入统一的 OAuth2 服务

This commit is contained in:
YunaiV
2019-05-17 00:35:42 +08:00
parent be94f29791
commit 68027b9f16
28 changed files with 229 additions and 178 deletions

View File

@@ -1,8 +1,9 @@
package cn.iocoder.mall.user.biz.convert;
import cn.iocoder.mall.user.biz.dataobject.UserDO;
import cn.iocoder.mall.user.api.bo.user.UserAuthenticationBO;
import cn.iocoder.mall.user.api.bo.UserBO;
import cn.iocoder.mall.user.api.dto.UserUpdateDTO;
import cn.iocoder.mall.user.biz.dataobject.UserDO;
import org.mapstruct.Mapper;
import org.mapstruct.Mappings;
import org.mapstruct.factory.Mappers;
@@ -17,10 +18,13 @@ public interface UserConvert {
@Mappings({})
UserBO convert(UserDO userDO);
@Mappings({})
UserAuthenticationBO convert2(UserDO userDO);
@Mappings({})
UserDO convert(UserUpdateDTO userUpdateDTO);
@Mappings({})
List<UserBO> convert(List<UserDO> userDOs);
}
}

View File

@@ -1,19 +1,12 @@
package cn.iocoder.mall.user.biz.dao;
import cn.iocoder.mall.user.biz.dataobject.MobileCodeDO;
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 {
void insert(MobileCodeDO entity);
/**
* 更新手机验证码
*
* @param entity 更新信息
*/
void update(MobileCodeDO entity);
public interface MobileCodeMapper extends BaseMapper<MobileCodeDO> {
/**
* 获得手机号的最后一个手机验证码
@@ -21,6 +14,12 @@ public interface MobileCodeMapper {
* @param mobile 手机号
* @return 手机验证码
*/
MobileCodeDO selectLast1ByMobile(String mobile);
default MobileCodeDO selectLast1ByMobile(String mobile) {
QueryWrapper<MobileCodeDO> query = new QueryWrapper<MobileCodeDO>()
.eq("mobile", mobile)
.orderByDesc("id")
.last("limit 1");
return selectOne(query);
}
}
}

View File

@@ -1,14 +1,17 @@
package cn.iocoder.mall.user.biz.dataobject;
import cn.iocoder.common.framework.dataobject.BaseDO;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import lombok.experimental.Accessors;
import java.util.Date;
// TODO 优化IP
@TableName("mobile_code")
@Data
@Accessors(chain = true)
public class MobileCodeDO {
public class MobileCodeDO extends BaseDO {
/**
* 编号
@@ -34,10 +37,6 @@ public class MobileCodeDO {
* 注册的用户编号
*/
private Integer usedUserId;
/**
* 创建时间
*/
private Date createTime;
/**
* 使用时间
*/

View File

@@ -50,21 +50,21 @@ public class MobileCodeServiceImpl implements MobileCodeService {
*/
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) { // 若验证码不存在,抛出异常
// 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;
// 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;
}
/**
@@ -75,7 +75,7 @@ public class MobileCodeServiceImpl implements MobileCodeService {
*/
public void useMobileCode(Integer id, Integer userId) {
MobileCodeDO update = new MobileCodeDO().setId(id).setUsed(true).setUsedUserId(userId).setUsedTime(new Date());
mobileCodeMapper.update(update);
mobileCodeMapper.updateById(update);
}
// TODO 芋艿,后面要返回有效时间
@@ -99,7 +99,8 @@ public class MobileCodeServiceImpl implements MobileCodeService {
MobileCodeDO newMobileCodePO = new MobileCodeDO().setMobile(mobile)
.setCode("9999") // TODO 芋艿,随机 4 位验证码 or 6 位验证码
.setTodayIndex(lastMobileCodePO != null ? lastMobileCodePO.getTodayIndex() : 1)
.setUsed(false).setCreateTime(new Date());
.setUsed(false);
newMobileCodePO.setCreateTime(new Date());
mobileCodeMapper.insert(newMobileCodePO);
// TODO 发送验证码短信
}

View File

@@ -49,27 +49,6 @@ public class OAuth2ServiceImpl implements OAuth2Service {
@Autowired
private OAuth2RefreshTokenMapper oauth2RefreshTokenMapper;
@Override
@Transactional
public OAuth2AccessTokenBO getAccessToken(String mobile, String code) {
// 校验传入的 mobile 和 code 是否合法
MobileCodeDO mobileCodeDO = mobileCodeService.validLastMobileCode(mobile, code);
// 获取用户
UserDO userDO = userService.getUser(mobile);
if (userDO == null) { // 用户不存在,则进行创建用户
userDO = userService.createUser(mobile);
Assert.notNull(userDO, "创建用户必然成功");
}
// 创建刷新令牌
OAuth2RefreshTokenDO oauth2RefreshTokenDO = createOAuth2RefreshToken(userDO.getId());
// 创建访问令牌
OAuth2AccessTokenDO oauth2AccessTokenDO = createOAuth2AccessToken(userDO.getId(), oauth2RefreshTokenDO.getId());
// 标记已使用
mobileCodeService.useMobileCode(mobileCodeDO.getId(), userDO.getId());
// 转换返回
return OAuth2Convert.INSTANCE.convertToAccessTokenWithExpiresIn(oauth2AccessTokenDO);
}
@Override
public OAuth2AuthenticationBO checkToken(String accessToken) throws ServiceException {
OAuth2AccessTokenDO accessTokenDO = oauth2AccessTokenMapper.selectByTokenId(accessToken);

View File

@@ -3,20 +3,28 @@ package cn.iocoder.mall.user.biz.service;
import cn.iocoder.common.framework.constant.CommonStatusEnum;
import cn.iocoder.common.framework.constant.DeletedStatusEnum;
import cn.iocoder.common.framework.constant.SysErrorCodeEnum;
import cn.iocoder.common.framework.constant.UserTypeEnum;
import cn.iocoder.common.framework.util.ServiceExceptionUtil;
import cn.iocoder.common.framework.util.ValidationUtil;
import cn.iocoder.mall.admin.api.OAuth2Service;
import cn.iocoder.mall.admin.api.bo.oauth2.OAuth2AccessTokenBO;
import cn.iocoder.mall.admin.api.dto.oauth2.OAuth2CreateTokenDTO;
import cn.iocoder.mall.user.api.UserService;
import cn.iocoder.mall.user.api.bo.user.UserAuthenticationBO;
import cn.iocoder.mall.user.api.bo.UserBO;
import cn.iocoder.mall.user.api.bo.UserPageBO;
import cn.iocoder.mall.user.api.constant.UserConstants;
import cn.iocoder.mall.user.api.constant.UserErrorCodeEnum;
import cn.iocoder.mall.user.api.dto.UserPageDTO;
import cn.iocoder.mall.user.api.dto.UserUpdateDTO;
import cn.iocoder.mall.user.api.dto.user.UserAuthenticationByMobileCodeDTO;
import cn.iocoder.mall.user.biz.convert.UserConvert;
import cn.iocoder.mall.user.biz.dao.UserMapper;
import cn.iocoder.mall.user.biz.dao.UserRegisterMapper;
import cn.iocoder.mall.user.biz.dataobject.MobileCodeDO;
import cn.iocoder.mall.user.biz.dataobject.UserDO;
import cn.iocoder.mall.user.biz.dataobject.UserRegisterDO;
import org.apache.dubbo.config.annotation.Reference;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@@ -35,7 +43,10 @@ public class UserServiceImpl implements UserService {
@Autowired
private UserRegisterMapper userRegisterMapper;
@Autowired
private OAuth2ServiceImpl oAuth2Service;
private MobileCodeServiceImpl mobileCodeService;
@Reference(validation = "true", version = "${dubbo.consumer.OAuth2Service.version}")
private OAuth2Service oAuth2Service;
public UserDO getUser(String mobile) {
return userMapper.selectByMobile(mobile);
@@ -67,6 +78,36 @@ public class UserServiceImpl implements UserService {
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
public UserPageBO getUserPage(UserPageDTO userPageDTO) {
UserPageBO userPageBO = new UserPageBO();

View File

@@ -6,19 +6,17 @@ spring:
username: root
password: ${MALL_MYSQL_PASSWORD}
# mybatis
#mybatis:
# config-location: classpath:mybatis-config.xml
# mapper-locations: classpath:mapper/*.xml
# type-aliases-package: cn.iocoder.mall.user.biz.dataobject
# mybatis-plus
mybatis-plus:
configuration:
mapUnderscoreToCamelCase: true # 虽然默认为 true ,但是还是显示去指定下。
map-underscore-to-camel-case: true # 虽然默认为 true ,但是还是显示去指定下。
global-config:
db-config:
id-type: auto
logic-delete-value: 1 # 逻辑已删除值(默认为 1)
logic-not-delete-value: 0 # 逻辑未删除值(默认为 0)
mapperLocations: classpath*:mapper/*.xml
typeAliasesPackage: cn.iocoder.mall.user.biz.dataobject
config-location: classpath:mybatis-config.xml
# dubbo
dubbo:
@@ -43,3 +41,6 @@ dubbo:
version: 1.0.0
UserService:
version: 1.0.0
consumer:
OAuth2Service:
version: 1.0.0

View File

@@ -1,35 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="cn.iocoder.mall.user.biz.dao.MobileCodeMapper">
<insert id="insert" parameterType="MobileCodeDO">
INSERT INTO mobile_code (
id, mobile, code, today_index, used,
userd_user_id, used_time, create_time
) VALUES (
#{id}, #{mobile}, #{code}, #{todayIndex}, #{used},
#{usedUserId}, #{usedTime}, #{createTime}
)
</insert>
<update id="update" parameterType="MobileCodeDO">
UPDATE mobile_code
<set>
<if test="used != null"> used = #{used}, </if>
<if test="usedUserId != null"> userd_user_id = #{usedUserId}, </if>
<if test="usedTime != null"> used_time = #{usedTime}, </if>
</set>
WHERE id = #{id}
</update>
<select id="selectLast1ByMobile" parameterType="String" resultType="MobileCodeDO">
SELECT
id, mobile, code, today_index, used,
userd_user_id, used_time, create_time
FROM mobile_code
WHERE mobile = #{mobile}
ORDER BY id DESC
LIMIT 1
</select>
</mapper>

View File

@@ -1,19 +0,0 @@
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<settings>
<!-- 使用驼峰命名法转换字段。 -->
<setting name="mapUnderscoreToCamelCase" value="true"/>
</settings>
<typeAliases>
<typeAlias alias="Integer" type="java.lang.Integer"/>
<typeAlias alias="Long" type="java.lang.Long"/>
<typeAlias alias="HashMap" type="java.util.HashMap"/>
<typeAlias alias="LinkedHashMap" type="java.util.LinkedHashMap"/>
<typeAlias alias="ArrayList" type="java.util.ArrayList"/>
<typeAlias alias="LinkedList" type="java.util.LinkedList"/>
</typeAliases>
</configuration>