多模块重构 4:system 模块的调整,完成 social 的复用

This commit is contained in:
YunaiV 2022-01-31 10:07:27 +08:00
parent 14097b4120
commit 638b8b1dd4
7 changed files with 114 additions and 76 deletions

View File

@ -26,10 +26,10 @@ public interface AuthConvert {
return convert0(bean).setUserType(UserTypeEnum.MEMBER.getValue()); return convert0(bean).setUserType(UserTypeEnum.MEMBER.getValue());
} }
SocialUserBindReqDTO convert(Long userId, Integer value, AppAuthSocialBindReqVO reqVO); SocialUserBindReqDTO convert(Long userId, Integer userType, AppAuthSocialBindReqVO reqVO);
SocialUserBindReqDTO convert(Long userId, Integer value, AppAuthSocialLogin2ReqVO reqVO); SocialUserBindReqDTO convert(Long userId, Integer userType, AppAuthSocialLogin2ReqVO reqVO);
SocialUserBindReqDTO convert(Long userId, Integer value, AppAuthSocialLoginReqVO reqVO); SocialUserBindReqDTO convert(Long userId, Integer userType, AppAuthSocialLoginReqVO reqVO);
SocialUserUnbindReqDTO convert(Long userId, Integer value, AppAuthSocialUnbindReqVO reqVO); SocialUserUnbindReqDTO convert(Long userId, Integer userType, AppAuthSocialUnbindReqVO reqVO);
SmsCodeSendReqDTO convert(AppAuthSendSmsReqVO reqVO); SmsCodeSendReqDTO convert(AppAuthSendSmsReqVO reqVO);
SmsCodeUseReqDTO convert(AppAuthResetPasswordReqVO reqVO, SmsSceneEnum scene, String usedIp); SmsCodeUseReqDTO convert(AppAuthResetPasswordReqVO reqVO, SmsSceneEnum scene, String usedIp);

View File

@ -152,6 +152,7 @@ public class MemberAuthServiceImpl implements MemberAuthService {
@Override @Override
public void socialBind(Long userId, AppAuthSocialBindReqVO reqVO) { public void socialBind(Long userId, AppAuthSocialBindReqVO reqVO) {
// 绑定社交用户新增
socialUserApi.bindSocialUser(AuthConvert.INSTANCE.convert(userId, getUserType().getValue(), reqVO)); socialUserApi.bindSocialUser(AuthConvert.INSTANCE.convert(userId, getUserType().getValue(), reqVO));
} }

View File

@ -3,15 +3,11 @@ package cn.iocoder.yudao.module.system.api.social;
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.service.social.SocialUserService; import cn.iocoder.yudao.module.system.service.social.SocialUserService;
import me.zhyd.oauth.model.AuthUser;
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 static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.SOCIAL_USER_NOT_FOUND;
/** /**
* 社交用户的 API 实现类 * 社交用户的 API 实现类
* *
@ -31,16 +27,7 @@ public class SocialUserApiImpl implements SocialUserApi {
@Override @Override
public void bindSocialUser(SocialUserBindReqDTO reqDTO) { public void bindSocialUser(SocialUserBindReqDTO reqDTO) {
// 使用 code 授权 socialUserService.bindSocialUser(reqDTO);
AuthUser authUser = socialUserService.getAuthUser(reqDTO.getType(), reqDTO.getCode(),
reqDTO.getState());
if (authUser == null) {
throw exception(SOCIAL_USER_NOT_FOUND);
}
// 绑定社交用户新增
socialUserService.bindSocialUser(reqDTO.getUserId(), reqDTO.getUserType(),
reqDTO.getType(), authUser);
} }
@Override @Override
@ -51,21 +38,12 @@ public class SocialUserApiImpl implements SocialUserApi {
@Override @Override
public void checkSocialUser(Integer type, String code, String state) { public void checkSocialUser(Integer type, String code, String state) {
AuthUser authUser = socialUserService.getAuthUser(type, code, state); socialUserService.checkSocialUser(type, code, state);
if (authUser == null) {
throw exception(SOCIAL_USER_NOT_FOUND);
}
} }
@Override @Override
public Long getBindUserId(Integer userType, Integer type, String code, String state) { public Long getBindUserId(Integer userType, Integer type, String code, String state) {
AuthUser authUser = socialUserService.getAuthUser(type, code, state); return socialUserService.getBindUserId(userType, type, code, state);
if (authUser == null) {
throw exception(SOCIAL_USER_NOT_FOUND);
}
//
return null;
} }
} }

View File

@ -1,14 +1,15 @@
package cn.iocoder.yudao.module.system.convert.auth; package cn.iocoder.yudao.module.system.convert.auth;
import cn.iocoder.yudao.module.system.controller.admin.auth.vo.auth.AuthMenuRespVO; import cn.iocoder.yudao.framework.common.enums.UserTypeEnum;
import cn.iocoder.yudao.module.system.controller.admin.auth.vo.auth.AuthPermissionInfoRespVO; import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
import cn.iocoder.yudao.framework.security.core.LoginUser;
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.controller.admin.auth.vo.auth.*;
import cn.iocoder.yudao.module.system.dal.dataobject.permission.MenuDO; import cn.iocoder.yudao.module.system.dal.dataobject.permission.MenuDO;
import cn.iocoder.yudao.module.system.dal.dataobject.permission.RoleDO; import cn.iocoder.yudao.module.system.dal.dataobject.permission.RoleDO;
import cn.iocoder.yudao.module.system.dal.dataobject.user.AdminUserDO; import cn.iocoder.yudao.module.system.dal.dataobject.user.AdminUserDO;
import cn.iocoder.yudao.module.system.enums.permission.MenuIdEnum; import cn.iocoder.yudao.module.system.enums.permission.MenuIdEnum;
import cn.iocoder.yudao.framework.common.enums.UserTypeEnum;
import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
import cn.iocoder.yudao.framework.security.core.LoginUser;
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;
@ -71,4 +72,9 @@ public interface AuthConvert {
return CollectionUtils.filterList(treeNodeMap.values(), node -> MenuIdEnum.ROOT.getId().equals(node.getParentId())); return CollectionUtils.filterList(treeNodeMap.values(), node -> MenuIdEnum.ROOT.getId().equals(node.getParentId()));
} }
SocialUserBindReqDTO convert(Long userId, Integer userType, AuthSocialBindReqVO reqVO);
SocialUserBindReqDTO convert(Long userId, Integer userType, AuthSocialLogin2ReqVO reqVO);
SocialUserBindReqDTO convert(Long userId, Integer userType, AuthSocialLoginReqVO reqVO);
SocialUserUnbindReqDTO convert(Long userId, Integer userType, AuthSocialUnbindReqVO reqVO);
} }

View File

@ -1,6 +1,5 @@
package cn.iocoder.yudao.module.system.service.auth; package cn.iocoder.yudao.module.system.service.auth;
import cn.hutool.core.collection.CollUtil;
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
import cn.iocoder.yudao.framework.common.enums.UserTypeEnum; import cn.iocoder.yudao.framework.common.enums.UserTypeEnum;
import cn.iocoder.yudao.framework.common.util.monitor.TracerUtils; import cn.iocoder.yudao.framework.common.util.monitor.TracerUtils;
@ -12,7 +11,6 @@ import cn.iocoder.yudao.module.system.controller.admin.auth.vo.auth.AuthSocialBi
import cn.iocoder.yudao.module.system.controller.admin.auth.vo.auth.AuthSocialLogin2ReqVO; import cn.iocoder.yudao.module.system.controller.admin.auth.vo.auth.AuthSocialLogin2ReqVO;
import cn.iocoder.yudao.module.system.controller.admin.auth.vo.auth.AuthSocialLoginReqVO; import cn.iocoder.yudao.module.system.controller.admin.auth.vo.auth.AuthSocialLoginReqVO;
import cn.iocoder.yudao.module.system.convert.auth.AuthConvert; import cn.iocoder.yudao.module.system.convert.auth.AuthConvert;
import cn.iocoder.yudao.module.system.dal.dataobject.social.SocialUserDO;
import cn.iocoder.yudao.module.system.dal.dataobject.user.AdminUserDO; import cn.iocoder.yudao.module.system.dal.dataobject.user.AdminUserDO;
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;
@ -37,7 +35,6 @@ import org.springframework.stereotype.Service;
import org.springframework.util.Assert; import org.springframework.util.Assert;
import javax.annotation.Resource; import javax.annotation.Resource;
import java.util.List;
import java.util.Objects; import java.util.Objects;
import java.util.Set; import java.util.Set;
@ -70,7 +67,7 @@ public class AdminAuthServiceImpl implements AdminAuthService {
@Resource @Resource
private UserSessionService userSessionService; private UserSessionService userSessionService;
@Resource @Resource
private SocialUserService socialService; private SocialUserService socialUserService;
@Override @Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
@ -192,19 +189,15 @@ public class AdminAuthServiceImpl implements AdminAuthService {
@Override @Override
public String socialLogin(AuthSocialLoginReqVO reqVO, String userIp, String userAgent) { public String socialLogin(AuthSocialLoginReqVO reqVO, String userIp, String userAgent) {
// 使用 code 授权码进行登录 // 使用 code 授权码进行登录然后获得到绑定的用户编号
AuthUser authUser = socialService.getAuthUser(reqVO.getType(), reqVO.getCode(), reqVO.getState()); Long userId = socialUserService.getBindUserId(UserTypeEnum.MEMBER.getValue(), reqVO.getType(),
Assert.notNull(authUser, "授权用户不为空"); reqVO.getCode(), reqVO.getState());
if (userId == null) {
// 如果未绑定 SocialUserDO 用户则无法自动登录进行报错
String unionId = socialService.getAuthUserUnionId(authUser);
List<SocialUserDO> socialUsers = socialService.getAllSocialUserList(reqVO.getType(), unionId, getUserType().getValue());
if (CollUtil.isEmpty(socialUsers)) {
throw exception(AUTH_THIRD_LOGIN_NOT_BIND); throw exception(AUTH_THIRD_LOGIN_NOT_BIND);
} }
// 自动登录 // 自动登录
AdminUserDO user = userService.getUser(socialUsers.get(0).getUserId()); AdminUserDO user = userService.getUser(userId);
if (user == null) { if (user == null) {
throw exception(USER_NOT_EXISTS); throw exception(USER_NOT_EXISTS);
} }
@ -214,7 +207,7 @@ public class AdminAuthServiceImpl implements AdminAuthService {
LoginUser loginUser = this.buildLoginUser(user); LoginUser loginUser = this.buildLoginUser(user);
// 绑定社交用户更新 // 绑定社交用户更新
socialService.bindSocialUser(loginUser.getId(), getUserType().getValue(), reqVO.getType(), authUser); socialUserService.bindSocialUser(AuthConvert.INSTANCE.convert(loginUser.getId(), getUserType().getValue(), reqVO));
// 缓存登录用户到 Redis 返回 sessionId 编号 // 缓存登录用户到 Redis 返回 sessionId 编号
return userSessionService.createUserSession(loginUser, userIp, userAgent); return userSessionService.createUserSession(loginUser, userIp, userAgent);
@ -223,14 +216,14 @@ public class AdminAuthServiceImpl implements AdminAuthService {
@Override @Override
public String socialLogin2(AuthSocialLogin2ReqVO reqVO, String userIp, String userAgent) { public String socialLogin2(AuthSocialLogin2ReqVO reqVO, String userIp, String userAgent) {
// 使用 code 授权码进行登录 // 使用 code 授权码进行登录
AuthUser authUser = socialService.getAuthUser(reqVO.getType(), reqVO.getCode(), reqVO.getState()); AuthUser authUser = socialUserService.getAuthUser(reqVO.getType(), reqVO.getCode(), reqVO.getState());
Assert.notNull(authUser, "授权用户不为空"); Assert.notNull(authUser, "授权用户不为空");
// 使用账号密码进行登录 // 使用账号密码进行登录
LoginUser loginUser = this.login0(reqVO.getUsername(), reqVO.getPassword()); LoginUser loginUser = this.login0(reqVO.getUsername(), reqVO.getPassword());
// 绑定社交用户新增 // 绑定社交用户新增
socialService.bindSocialUser(loginUser.getId(), getUserType().getValue(), reqVO.getType(), authUser); socialUserService.bindSocialUser(AuthConvert.INSTANCE.convert(loginUser.getId(), getUserType().getValue(), reqVO));
// 缓存登录用户到 Redis 返回 sessionId 编号 // 缓存登录用户到 Redis 返回 sessionId 编号
return userSessionService.createUserSession(loginUser, userIp, userAgent); return userSessionService.createUserSession(loginUser, userIp, userAgent);
@ -238,12 +231,8 @@ public class AdminAuthServiceImpl implements AdminAuthService {
@Override @Override
public void socialBind(Long userId, AuthSocialBindReqVO reqVO) { public void socialBind(Long userId, AuthSocialBindReqVO reqVO) {
// 使用 code 授权码进行登录
AuthUser authUser = socialService.getAuthUser(reqVO.getType(), reqVO.getCode(), reqVO.getState());
Assert.notNull(authUser, "授权用户不为空");
// 绑定社交用户新增 // 绑定社交用户新增
socialService.bindSocialUser(userId, getUserType().getValue(), reqVO.getType(), authUser); socialUserService.bindSocialUser(AuthConvert.INSTANCE.convert(userId, getUserType().getValue(), reqVO));
} }
@Override @Override

View File

@ -2,10 +2,12 @@ package cn.iocoder.yudao.module.system.service.social;
import cn.hutool.core.util.StrUtil; import cn.hutool.core.util.StrUtil;
import cn.iocoder.yudao.framework.common.exception.ServiceException; import cn.iocoder.yudao.framework.common.exception.ServiceException;
import cn.iocoder.yudao.module.system.api.social.dto.SocialUserBindReqDTO;
import cn.iocoder.yudao.module.system.dal.dataobject.social.SocialUserDO; import cn.iocoder.yudao.module.system.dal.dataobject.social.SocialUserDO;
import cn.iocoder.yudao.module.system.enums.social.SocialTypeEnum; import cn.iocoder.yudao.module.system.enums.social.SocialTypeEnum;
import me.zhyd.oauth.model.AuthUser; import me.zhyd.oauth.model.AuthUser;
import javax.validation.Valid;
import javax.validation.constraints.NotNull; import javax.validation.constraints.NotNull;
import java.util.List; import java.util.List;
@ -47,17 +49,6 @@ public interface SocialUserService {
return StrUtil.blankToDefault(authUser.getToken().getUnionId(), authUser.getUuid()); return StrUtil.blankToDefault(authUser.getToken().getUnionId(), authUser.getUuid());
} }
/**
* 获得 unionId 对应的某个社交平台的所有社交用户
* 注意这里的所有指的是类似微信平台包括了小程序公众号PC 网站他们的 unionId 是一致的
*
* @param type 社交平台的类型 {@link SocialTypeEnum}
* @param unionId 社交平台的 unionId
* @param userType 全局用户类型
* @return 社交用户列表
*/
List<SocialUserDO> getAllSocialUserList(Integer type, String unionId, Integer userType);
/** /**
* 获得指定用户的社交用户列表 * 获得指定用户的社交用户列表
* *
@ -69,12 +60,10 @@ public interface SocialUserService {
/** /**
* 绑定社交用户 * 绑定社交用户
* @param userId 用户编号 *
* @param userType 用户类型 * @param reqDTO 绑定信息
* @param type 社交平台的类型 {@link SocialTypeEnum}
* @param authUser 授权用户
*/ */
void bindSocialUser(Long userId, Integer userType, Integer type, AuthUser authUser); void bindSocialUser(@Valid SocialUserBindReqDTO reqDTO);
/** /**
* 取消绑定社交用户 * 取消绑定社交用户
@ -86,4 +75,27 @@ public interface SocialUserService {
*/ */
void unbindSocialUser(Long userId, Integer userType, Integer type, String unionId); void unbindSocialUser(Long userId, Integer userType, Integer type, String unionId);
/**
* 校验社交用户的认证信息是否正确
* 如果校验不通过则抛出 {@link ServiceException} 业务异常
*
* @param type 社交平台的类型
* @param code 授权码
* @param state state
*/
void checkSocialUser(Integer type, String code, String state);
/**
* 获得社交用户的绑定用户编号
* 注意返回的是 MemberUser 或者 AdminUser id 编号
* 该方法会执行和 {@link #checkSocialUser(Integer, String, String)} 一样的逻辑
* 所以在认证信息不正确的情况下也会抛出 {@link ServiceException} 业务异常
*
* @param userType 用户类型
* @param type 社交平台的类型
* @param code 授权码
* @param state state
* @return 绑定用户编号
*/
Long getBindUserId(Integer userType, Integer type, String code, String state);
} }

View File

@ -3,6 +3,7 @@ package cn.iocoder.yudao.module.system.service.social;
import cn.hutool.core.collection.CollUtil; import cn.hutool.core.collection.CollUtil;
import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
import cn.iocoder.yudao.framework.common.util.http.HttpUtils; import cn.iocoder.yudao.framework.common.util.http.HttpUtils;
import cn.iocoder.yudao.module.system.api.social.dto.SocialUserBindReqDTO;
import cn.iocoder.yudao.module.system.dal.dataobject.social.SocialUserDO; import cn.iocoder.yudao.module.system.dal.dataobject.social.SocialUserDO;
import cn.iocoder.yudao.module.system.dal.mysql.social.SocialUserMapper; import cn.iocoder.yudao.module.system.dal.mysql.social.SocialUserMapper;
import cn.iocoder.yudao.module.system.dal.redis.social.SocialAuthUserRedisDAO; import cn.iocoder.yudao.module.system.dal.redis.social.SocialAuthUserRedisDAO;
@ -25,8 +26,7 @@ import java.util.Objects;
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.framework.common.util.json.JsonUtils.toJsonString; import static cn.iocoder.yudao.framework.common.util.json.JsonUtils.toJsonString;
import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.SOCIAL_USER_AUTH_FAILURE; import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.*;
import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.SOCIAL_USER_UNBIND_NOT_SELF;
/** /**
* 社交用户 Service 实现类 * 社交用户 Service 实现类
@ -72,8 +72,16 @@ public class SocialUserServiceImpl implements SocialUserService {
return authUser; return authUser;
} }
@Override /**
public List<SocialUserDO> getAllSocialUserList(Integer type, String unionId, Integer userType) { * 获得 unionId 对应的某个社交平台的所有社交用户
* 注意这里的所有指的是类似微信平台包括了小程序公众号PC 网站他们的 unionId 是一致的
*
* @param type 社交平台的类型 {@link SocialTypeEnum}
* @param unionId 社交平台的 unionId
* @param userType 全局用户类型
* @return 社交用户列表
*/
private List<SocialUserDO> getAllSocialUserList(Integer type, String unionId, Integer userType) {
List<Integer> types = SocialTypeEnum.getRelationTypes(type); List<Integer> types = SocialTypeEnum.getRelationTypes(type);
return socialUserMapper.selectListByTypeAndUnionId(userType, types, unionId); return socialUserMapper.selectListByTypeAndUnionId(userType, types, unionId);
} }
@ -84,8 +92,28 @@ public class SocialUserServiceImpl implements SocialUserService {
} }
@Override @Override
public void bindSocialUser(SocialUserBindReqDTO reqDTO) {
// 使用 code 授权
AuthUser authUser = getAuthUser(reqDTO.getType(), reqDTO.getCode(),
reqDTO.getState());
if (authUser == null) {
throw exception(SOCIAL_USER_NOT_FOUND);
}
// 绑定社交用户新增
bindSocialUser(reqDTO.getUserId(), reqDTO.getUserType(),
reqDTO.getType(), authUser);
}
/**
* 绑定社交用户
* @param userId 用户编号
* @param userType 用户类型
* @param type 社交平台的类型 {@link SocialTypeEnum}
* @param authUser 授权用户
*/
@Transactional(rollbackFor = Exception.class) @Transactional(rollbackFor = Exception.class)
public void bindSocialUser(Long userId, Integer userType, Integer type, AuthUser authUser) { protected void bindSocialUser(Long userId, Integer userType, Integer type, AuthUser authUser) {
// 获得 unionId 对应的 SocialUserDO 列表 // 获得 unionId 对应的 SocialUserDO 列表
String unionId = getAuthUserUnionId(authUser); String unionId = getAuthUserUnionId(authUser);
List<SocialUserDO> socialUsers = this.getAllSocialUserList(type, unionId, userType); List<SocialUserDO> socialUsers = this.getAllSocialUserList(type, unionId, userType);
@ -137,6 +165,30 @@ public class SocialUserServiceImpl implements SocialUserService {
socialUserMapper.deleteBatchIds(CollectionUtils.convertSet(socialUsers, SocialUserDO::getId)); socialUserMapper.deleteBatchIds(CollectionUtils.convertSet(socialUsers, SocialUserDO::getId));
} }
@Override
public void checkSocialUser(Integer type, String code, String state) {
AuthUser authUser = getAuthUser(type, code, state);
if (authUser == null) {
throw exception(SOCIAL_USER_NOT_FOUND);
}
}
@Override
public Long getBindUserId(Integer userType, Integer type, String code, String state) {
AuthUser authUser = getAuthUser(type, code, state);
if (authUser == null) {
throw exception(SOCIAL_USER_NOT_FOUND);
}
// 如果未绑定 SocialUserDO 用户则无法自动登录进行报错
String unionId = getAuthUserUnionId(authUser);
List<SocialUserDO> socialUsers = getAllSocialUserList(type, unionId, userType);
if (CollUtil.isEmpty(socialUsers)) {
throw exception(AUTH_THIRD_LOGIN_NOT_BIND);
}
return socialUsers.get(0).getUserId();
}
@VisibleForTesting @VisibleForTesting
public void unbindOldSocialUser(Long userId, Integer userType, Integer type, String newUnionId) { public void unbindOldSocialUser(Long userId, Integer userType, Integer type, String newUnionId) {
List<Integer> types = SocialTypeEnum.getRelationTypes(type); List<Integer> types = SocialTypeEnum.getRelationTypes(type);