|  | @@ -4,6 +4,7 @@ import cn.hutool.core.collection.CollUtil;
 | 
	
		
			
				|  |  |  import cn.hutool.core.lang.Assert;
 | 
	
		
			
				|  |  |  import cn.newfeifan.mall.framework.common.exception.ServiceException;
 | 
	
		
			
				|  |  |  import cn.newfeifan.mall.framework.common.pojo.PageResult;
 | 
	
		
			
				|  |  | +import cn.newfeifan.mall.framework.common.util.json.JsonUtils;
 | 
	
		
			
				|  |  |  import cn.newfeifan.mall.module.system.api.social.dto.SocialUserBindReqDTO;
 | 
	
		
			
				|  |  |  import cn.newfeifan.mall.module.system.api.social.dto.SocialUserRespDTO;
 | 
	
		
			
				|  |  |  import cn.newfeifan.mall.module.system.controller.admin.socail.vo.user.SocialUserPageReqVO;
 | 
	
	
		
			
				|  | @@ -12,8 +13,10 @@ import cn.newfeifan.mall.module.system.dal.dataobject.social.SocialUserDO;
 | 
	
		
			
				|  |  |  import cn.newfeifan.mall.module.system.dal.mysql.social.SocialUserBindMapper;
 | 
	
		
			
				|  |  |  import cn.newfeifan.mall.module.system.dal.mysql.social.SocialUserMapper;
 | 
	
		
			
				|  |  |  import cn.newfeifan.mall.module.system.enums.social.SocialTypeEnum;
 | 
	
		
			
				|  |  | +import com.alibaba.fastjson.JSONObject;
 | 
	
		
			
				|  |  |  import com.xingyuv.jushauth.model.AuthUser;
 | 
	
		
			
				|  |  |  import lombok.extern.slf4j.Slf4j;
 | 
	
		
			
				|  |  | +import org.springframework.data.redis.core.StringRedisTemplate;
 | 
	
		
			
				|  |  |  import org.springframework.stereotype.Service;
 | 
	
		
			
				|  |  |  import org.springframework.transaction.annotation.Transactional;
 | 
	
		
			
				|  |  |  import org.springframework.validation.annotation.Validated;
 | 
	
	
		
			
				|  | @@ -22,6 +25,7 @@ import javax.annotation.Resource;
 | 
	
		
			
				|  |  |  import javax.validation.constraints.NotNull;
 | 
	
		
			
				|  |  |  import java.util.Collections;
 | 
	
		
			
				|  |  |  import java.util.List;
 | 
	
		
			
				|  |  | +import java.util.concurrent.TimeUnit;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  import static cn.newfeifan.mall.framework.common.exception.util.ServiceExceptionUtil.exception;
 | 
	
		
			
				|  |  |  import static cn.newfeifan.mall.framework.common.util.collection.CollectionUtils.convertSet;
 | 
	
	
		
			
				|  | @@ -46,6 +50,9 @@ public class SocialUserServiceImpl implements SocialUserService {
 | 
	
		
			
				|  |  |      @Resource
 | 
	
		
			
				|  |  |      private SocialClientService socialClientService;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +    @Resource
 | 
	
		
			
				|  |  | +    private StringRedisTemplate stringRedisTemplate;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |      @Override
 | 
	
		
			
				|  |  |      public List<SocialUserDO> getSocialUserList(Long userId, Integer userType) {
 | 
	
		
			
				|  |  |          // 获得绑定
 | 
	
	
		
			
				|  | @@ -118,10 +125,11 @@ public class SocialUserServiceImpl implements SocialUserService {
 | 
	
		
			
				|  |  |          return new SocialUserRespDTO(socialUser.getOpenid(), socialUser.getNickname(), socialUser.getAvatar(),
 | 
	
		
			
				|  |  |                  socialUserBind != null ? socialUserBind.getUserId() : null);
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |      @Override
 | 
	
		
			
				|  |  | -    public SocialUserRespDTO getSocialUserByCode(Integer userType, Integer socialType, String code, String state, Boolean isFirst) {
 | 
	
		
			
				|  |  | +    public SocialUserRespDTO getSocialUserByCode(Integer userType, Integer socialType, String code, String state, Boolean isFirst, Boolean isRegister) {
 | 
	
		
			
				|  |  |          // 获得社交用户
 | 
	
		
			
				|  |  | -        SocialUserDO socialUser = authSocialUser(socialType, userType, code, state,isFirst);
 | 
	
		
			
				|  |  | +        SocialUserDO socialUser = authSocialUser(socialType, userType, code, state, isFirst, isRegister);
 | 
	
		
			
				|  |  |          Assert.notNull(socialUser, "社交用户不能为空");
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |          // 获得绑定用户
 | 
	
	
		
			
				|  | @@ -132,7 +140,7 @@ public class SocialUserServiceImpl implements SocialUserService {
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |      public SocialUserDO authSocialUser(Integer socialType, Integer userType, String code, String state) {
 | 
	
		
			
				|  |  | -        return this.authSocialUser(socialType, userType, code, state, false);
 | 
	
		
			
				|  |  | +        return this.authSocialUser(socialType, userType, code, state, false, false);
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |      /**
 | 
	
	
		
			
				|  | @@ -140,13 +148,13 @@ public class SocialUserServiceImpl implements SocialUserService {
 | 
	
		
			
				|  |  |       * 如果授权失败,则会抛出 {@link ServiceException} 异常
 | 
	
		
			
				|  |  |       *
 | 
	
		
			
				|  |  |       * @param socialType 社交平台的类型 {@link SocialTypeEnum}
 | 
	
		
			
				|  |  | -     * @param userType 用户类型
 | 
	
		
			
				|  |  | -     * @param code     授权码
 | 
	
		
			
				|  |  | -     * @param state    state
 | 
	
		
			
				|  |  | +     * @param userType   用户类型
 | 
	
		
			
				|  |  | +     * @param code       授权码
 | 
	
		
			
				|  |  | +     * @param state      state
 | 
	
		
			
				|  |  |       * @return 授权用户
 | 
	
		
			
				|  |  |       */
 | 
	
		
			
				|  |  |      @NotNull
 | 
	
		
			
				|  |  | -    public SocialUserDO authSocialUser(Integer socialType, Integer userType, String code, String state, boolean isFirst) {
 | 
	
		
			
				|  |  | +    public SocialUserDO authSocialUser(Integer socialType, Integer userType, String code, String state, Boolean isFirst, Boolean isRegister) {
 | 
	
		
			
				|  |  |          // 优先从 DB 中获取,因为 code 有且可以使用一次。
 | 
	
		
			
				|  |  |          // 在社交登录时,当未绑定 User 时,需要绑定登录,此时需要 code 使用两次
 | 
	
		
			
				|  |  |          SocialUserDO socialUser = socialUserMapper.selectByTypeAndCodeAnState(socialType, code, state);
 | 
	
	
		
			
				|  | @@ -154,13 +162,22 @@ public class SocialUserServiceImpl implements SocialUserService {
 | 
	
		
			
				|  |  |              return socialUser;
 | 
	
		
			
				|  |  |          }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -        // 请求获取
 | 
	
		
			
				|  |  | -        AuthUser authUser = socialClientService.getAuthUser(socialType, userType, code, state);
 | 
	
		
			
				|  |  | +        AuthUser authUser;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        if (isRegister) {
 | 
	
		
			
				|  |  | +            //如果已经走过首次登录,则从缓存里面拿取code
 | 
	
		
			
				|  |  | +            authUser = getAuthUser(code);
 | 
	
		
			
				|  |  | +        } else {
 | 
	
		
			
				|  |  | +            // 请求获取
 | 
	
		
			
				|  |  | +            authUser =socialClientService.getAuthUser(socialType, userType, code, state);
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  |          Assert.notNull(authUser, "三方用户不能为空");
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |          // 保存到 DB 中
 | 
	
		
			
				|  |  |          socialUser = socialUserMapper.selectByTypeAndOpenid(socialType, authUser.getUuid());
 | 
	
		
			
				|  |  |          if (isFirst && socialUser == null) {
 | 
	
		
			
				|  |  | +            //首次登录就将code缓存到redis中
 | 
	
		
			
				|  |  | +            stringRedisTemplate.opsForValue().set("auth_user:" + code, JsonUtils.toJsonString(authUser) , 60 * 10 , TimeUnit.SECONDS);
 | 
	
		
			
				|  |  |              throw exception(AUTH_LOGIN_USER_IS_FIRST);
 | 
	
		
			
				|  |  |          }
 | 
	
		
			
				|  |  |          if (socialUser == null) {
 | 
	
	
		
			
				|  | @@ -178,6 +195,27 @@ public class SocialUserServiceImpl implements SocialUserService {
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +    /**
 | 
	
		
			
				|  |  | +     * 根据代码获取认证用户信息。
 | 
	
		
			
				|  |  | +     *
 | 
	
		
			
				|  |  | +     * @param code 用户认证的唯一标识符。
 | 
	
		
			
				|  |  | +     * @return AuthUser 对象,如果找不到则返回null。
 | 
	
		
			
				|  |  | +     */
 | 
	
		
			
				|  |  | +    private AuthUser getAuthUser(String code) {
 | 
	
		
			
				|  |  | +        if (code == null || code.trim().isEmpty()) {
 | 
	
		
			
				|  |  | +            // 处理边界条件:无效的code
 | 
	
		
			
				|  |  | +            return null;
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +        String json = stringRedisTemplate.opsForValue().get("auth_user:" + code);
 | 
	
		
			
				|  |  | +        if (json != null) {
 | 
	
		
			
				|  |  | +            // 假设存在一个方法从JSON字符串中安全地解析AuthUser对象
 | 
	
		
			
				|  |  | +            return JSONObject.parseObject(json,AuthUser.class);
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        throw exception(AUTH_LOGIN_USER_ERROR_CODE);
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |      // ==================== 社交用户 CRUD ====================
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |      @Override
 |