houzhongjian
2024-09-14 818a0170d8f2950d52cc7300a302356bbc523236
提交 | 用户 | 时间
e7c126 1 package com.iailab.module.system.service.social;
H 2
3 import cn.hutool.core.collection.CollUtil;
4 import cn.hutool.core.lang.Assert;
5 import com.iailab.framework.common.exception.ServiceException;
6 import com.iailab.framework.common.pojo.PageResult;
7 import com.iailab.module.system.api.social.dto.SocialUserBindReqDTO;
8 import com.iailab.module.system.api.social.dto.SocialUserRespDTO;
9 import com.iailab.module.system.controller.admin.socail.vo.user.SocialUserPageReqVO;
10 import com.iailab.module.system.dal.dataobject.social.SocialUserBindDO;
11 import com.iailab.module.system.dal.dataobject.social.SocialUserDO;
12 import com.iailab.module.system.dal.mysql.social.SocialUserBindMapper;
13 import com.iailab.module.system.dal.mysql.social.SocialUserMapper;
14 import com.iailab.module.system.enums.social.SocialTypeEnum;
15 import com.xingyuv.jushauth.model.AuthUser;
16 import lombok.extern.slf4j.Slf4j;
17 import org.springframework.stereotype.Service;
18 import org.springframework.transaction.annotation.Transactional;
19 import org.springframework.validation.annotation.Validated;
20
21 import javax.annotation.Resource;
22 import javax.validation.constraints.NotNull;
23 import java.util.Collections;
24 import java.util.List;
25
26 import static com.iailab.framework.common.exception.util.ServiceExceptionUtil.exception;
27 import static com.iailab.framework.common.util.collection.CollectionUtils.convertSet;
28 import static com.iailab.framework.common.util.json.JsonUtils.toJsonString;
29 import static com.iailab.module.system.enums.ErrorCodeConstants.SOCIAL_USER_NOT_FOUND;
30
31 /**
32  * 社交用户 Service 实现类
33  *
34  * @author iailab
35  */
36 @Service
37 @Validated
38 @Slf4j
39 public class SocialUserServiceImpl implements SocialUserService {
40
41     @Resource
42     private SocialUserBindMapper socialUserBindMapper;
43     @Resource
44     private SocialUserMapper socialUserMapper;
45
46     @Resource
47     private SocialClientService socialClientService;
48
49     @Override
50     public List<SocialUserDO> getSocialUserList(Long userId, Integer userType) {
51         // 获得绑定
52         List<SocialUserBindDO> socialUserBinds = socialUserBindMapper.selectListByUserIdAndUserType(userId, userType);
53         if (CollUtil.isEmpty(socialUserBinds)) {
54             return Collections.emptyList();
55         }
56         // 获得社交用户
57         return socialUserMapper.selectBatchIds(convertSet(socialUserBinds, SocialUserBindDO::getSocialUserId));
58     }
59
60     @Override
61     @Transactional(rollbackFor = Exception.class)
62     public String bindSocialUser(SocialUserBindReqDTO reqDTO) {
63         // 获得社交用户
64         SocialUserDO socialUser = authSocialUser(reqDTO.getSocialType(), reqDTO.getUserType(),
65                 reqDTO.getCode(), reqDTO.getState());
66         Assert.notNull(socialUser, "社交用户不能为空");
67
68         // 社交用户可能之前绑定过别的用户,需要进行解绑
69         socialUserBindMapper.deleteByUserTypeAndSocialUserId(reqDTO.getUserType(), socialUser.getId());
70
71         // 用户可能之前已经绑定过该社交类型,需要进行解绑
72         socialUserBindMapper.deleteByUserTypeAndUserIdAndSocialType(reqDTO.getUserType(), reqDTO.getUserId(),
73                 socialUser.getType());
74
75         // 绑定当前登录的社交用户
76         SocialUserBindDO socialUserBind = SocialUserBindDO.builder()
77                 .userId(reqDTO.getUserId()).userType(reqDTO.getUserType())
78                 .socialUserId(socialUser.getId()).socialType(socialUser.getType()).build();
79         socialUserBindMapper.insert(socialUserBind);
80         return socialUser.getOpenid();
81     }
82
83     @Override
84     public void unbindSocialUser(Long userId, Integer userType, Integer socialType, String openid) {
85         // 获得 openid 对应的 SocialUserDO 社交用户
86         SocialUserDO socialUser = socialUserMapper.selectByTypeAndOpenid(socialType, openid);
87         if (socialUser == null) {
88             throw exception(SOCIAL_USER_NOT_FOUND);
89         }
90
91         // 获得对应的社交绑定关系
92         socialUserBindMapper.deleteByUserTypeAndUserIdAndSocialType(userType, userId, socialUser.getType());
93     }
94
95     @Override
96     public SocialUserRespDTO getSocialUserByUserId(Integer userType, Long userId, Integer socialType) {
97         // 获得绑定用户
98         SocialUserBindDO socialUserBind = socialUserBindMapper.selectByUserIdAndUserTypeAndSocialType(userId, userType, socialType);
99         if (socialUserBind == null) {
100             return null;
101         }
102         // 获得社交用户
103         SocialUserDO socialUser = socialUserMapper.selectById(socialUserBind.getSocialUserId());
104         Assert.notNull(socialUser, "社交用户不能为空");
105         return new SocialUserRespDTO(socialUser.getOpenid(), socialUser.getNickname(), socialUser.getAvatar(),
106                 socialUserBind.getUserId());
107     }
108
109     @Override
110     public SocialUserRespDTO getSocialUserByCode(Integer userType, Integer socialType, String code, String state) {
111         // 获得社交用户
112         SocialUserDO socialUser = authSocialUser(socialType, userType, code, state);
113         Assert.notNull(socialUser, "社交用户不能为空");
114
115         // 获得绑定用户
116         SocialUserBindDO socialUserBind = socialUserBindMapper.selectByUserTypeAndSocialUserId(userType,
117                 socialUser.getId());
118         return new SocialUserRespDTO(socialUser.getOpenid(), socialUser.getNickname(), socialUser.getAvatar(),
119                 socialUserBind != null ? socialUserBind.getUserId() : null);
120     }
121
122     /**
123      * 授权获得对应的社交用户
124      * 如果授权失败,则会抛出 {@link ServiceException} 异常
125      *
126      * @param socialType 社交平台的类型 {@link SocialTypeEnum}
127      * @param userType 用户类型
128      * @param code     授权码
129      * @param state    state
130      * @return 授权用户
131      */
132     @NotNull
133     public SocialUserDO authSocialUser(Integer socialType, Integer userType, String code, String state) {
134         // 优先从 DB 中获取,因为 code 有且可以使用一次。
135         // 在社交登录时,当未绑定 User 时,需要绑定登录,此时需要 code 使用两次
136         SocialUserDO socialUser = socialUserMapper.selectByTypeAndCodeAnState(socialType, code, state);
137         if (socialUser != null) {
138             return socialUser;
139         }
140
141         // 请求获取
142         AuthUser authUser = socialClientService.getAuthUser(socialType, userType, code, state);
143         Assert.notNull(authUser, "三方用户不能为空");
144
145         // 保存到 DB 中
146         socialUser = socialUserMapper.selectByTypeAndOpenid(socialType, authUser.getUuid());
147         if (socialUser == null) {
148             socialUser = new SocialUserDO();
149         }
150         socialUser.setType(socialType).setCode(code).setState(state) // 需要保存 code + state 字段,保证后续可查询
151                 .setOpenid(authUser.getUuid()).setToken(authUser.getToken().getAccessToken()).setRawTokenInfo((toJsonString(authUser.getToken())))
152                 .setNickname(authUser.getNickname()).setAvatar(authUser.getAvatar()).setRawUserInfo(toJsonString(authUser.getRawUserInfo()));
153         if (socialUser.getId() == null) {
154             socialUserMapper.insert(socialUser);
155         } else {
156             socialUserMapper.updateById(socialUser);
157         }
158         return socialUser;
159     }
160
161     // ==================== 社交用户 CRUD ====================
162
163     @Override
164     public SocialUserDO getSocialUser(Long id) {
165         return socialUserMapper.selectById(id);
166     }
167
168     @Override
169     public PageResult<SocialUserDO> getSocialUserPage(SocialUserPageReqVO pageReqVO) {
170         return socialUserMapper.selectPage(pageReqVO);
171     }
172
173 }