| | |
| | | import lombok.Setter; |
| | | import lombok.extern.slf4j.Slf4j; |
| | | import org.springframework.beans.factory.annotation.Value; |
| | | import org.springframework.beans.factory.annotation.Autowired; |
| | | import org.springframework.context.ApplicationEventPublisher; |
| | | import org.springframework.security.crypto.password.PasswordEncoder; |
| | | import org.springframework.stereotype.Service; |
| | |
| | | private RoleService roleService; |
| | | @Resource |
| | | private PermissionService permissionService; |
| | | @Autowired(required = false) |
| | | private WxcpMembershipRegistration wxcpMembershipRegistration; |
| | | @Resource |
| | | private WxcpPasswordSetupGrant wxcpPasswordSetupGrant; |
| | | |
| | | /** |
| | | * 验证码的开关,默认为 true |
| | |
| | | createLoginLog(null, username, logTypeEnum, LoginResultEnum.BAD_CREDENTIALS); |
| | | throw exception(AUTH_LOGIN_BAD_CREDENTIALS); |
| | | } |
| | | |
| | | if (!userService.isPasswordMatch(password, user.getPassword())) { |
| | | createLoginLog(user.getId(), username, logTypeEnum, LoginResultEnum.BAD_CREDENTIALS); |
| | | throw exception(AUTH_LOGIN_BAD_CREDENTIALS); |
| | |
| | | |
| | | // 如果 socialType 非空,说明需要绑定社交用户 |
| | | if (reqVO.getSocialType() != null) { |
| | | if (WECHAT_ENTERPRISE_TYPE.equals(reqVO.getSocialType())) { |
| | | SocialUserRespDTO social = socialUserService.getSocialUserByCode(getUserType().getValue(), |
| | | reqVO.getSocialType(), reqVO.getSocialCode(), reqVO.getSocialState()); |
| | | if (wxcpMembershipRegistration == null || social == null |
| | | || wxcpMembershipRegistration.hasPendingApplication(social.getOpenid())) { |
| | | throw exception(AUTH_WXCP_MEMBERSHIP_PENDING); |
| | | } |
| | | } |
| | | socialUserService.bindSocialUser(new SocialUserBindReqDTO(user.getId(), getUserType().getValue(), |
| | | reqVO.getSocialType(), reqVO.getSocialCode(), reqVO.getSocialState())); |
| | | } |
| | |
| | | } |
| | | |
| | | // 2. 判断是否已有绑定的系统用户 |
| | | // |
| | | // 注意:system_social_user_bind 里的 user_id 可能指向「已被删除」的用户 —— |
| | | // AdminUserServiceImpl.deleteUser 只清理了角色和岗位,没有清理这张社交绑定表, |
| | | // 删除后绑定关系会残留成孤儿。所以这里不能只看「有没有绑定」, |
| | | // 还要看「绑定的人还在不在」。 |
| | | Long bindUserId = socialUser.getUserId(); |
| | | AdminUserDO user; |
| | | AdminUserDO user = bindUserId != null ? userService.getUser(bindUserId) : null; |
| | | |
| | | if (bindUserId == null) { |
| | | // 2.1 首次登录:自动注册新用户 |
| | | if (user == null) { |
| | | if (WECHAT_ENTERPRISE_TYPE.equals(reqVO.getType())) { |
| | | if (wxcpMembershipRegistration == null) throw new IllegalStateException("会员注册服务不可用"); |
| | | wxcpMembershipRegistration.startIfAbsent(socialUser.getOpenid(), socialUser.getNickname(), socialUser.getMobile()); |
| | | return null; // 提交事务后由 Controller 返回待审核提示,不签发令牌 |
| | | } |
| | | // 2.1 首次登录,或原绑定用户已被删除:自动注册新用户并(改)绑定 |
| | | // |
| | | // 原绑定用户已删除时必须走这条路:否则该企业成员会永久卡在「用户不存在」—— |
| | | // 既登不进来,也不会被重新注册,是一个无法自愈的死锁。 |
| | | // bindSocialUser 内部会先删掉该社交用户的旧绑定,所以改绑不会产生重复记录。 |
| | | if (bindUserId != null) { |
| | | log.warn("[socialLogin][社交用户({}) 原绑定的用户({}) 已不存在(可能已被删除),按首次登录重新注册]", |
| | | socialUser.getOpenid(), bindUserId); |
| | | } |
| | | user = autoRegisterUser(socialUser, reqVO.getType()); |
| | | // 绑定社交账号 |
| | | socialUserService.bindSocialUser(new SocialUserBindReqDTO(user.getId(), getUserType().getValue(), |
| | | reqVO.getType(), reqVO.getCode(), reqVO.getState())); |
| | | log.info("[socialLogin][社交登录自动注册 userId={} username={} socialType={}]", |
| | | user.getId(), user.getUsername(), reqVO.getType()); |
| | | } else { |
| | | // 2.2 已有绑定:直接获取用户 |
| | | user = userService.getUser(bindUserId); |
| | | if (user == null) { |
| | | throw exception(USER_NOT_EXISTS); |
| | | } |
| | | } |
| | | |
| | | if (CommonStatusEnum.isDisable(user.getStatus())) throw exception(AUTH_LOGIN_USER_DISABLED); |
| | | // 3. 创建 Token 令牌,记录登录日志 |
| | | AuthLoginRespVO result = createTokenAfterLoginSuccess(user.getId(), user.getUsername(), LoginLogTypeEnum.LOGIN_SOCIAL); |
| | | if (WECHAT_ENTERPRISE_TYPE.equals(reqVO.getType())) { |
| | | wxcpPasswordSetupGrant.issue(result.getAccessToken(), user.getId()); |
| | | } |
| | | |
| | | // 4. 发布社交登录事件(供其他模块监听,如发送企业微信通知) |
| | | eventPublisher.publishEvent(new SocialLoginEvent( |
| | |
| | | |
| | | userService.updateUserPassword(userByMobile.getId(), reqVO.getPassword()); |
| | | } |
| | | } |
| | | } |