帮助文档
{{userInfo.nickname}}
用户设置 退出登录

{{wikiTitle}}

微信授权登录

一、功能概述

本模块实现微信多端授权登录(公众号、小程序、APP);
核心流程包括:OAuth2授权 → 用户身份识别 → 登录/注册分流 → 分销关系绑定 → Token签发。
以下是跨端登录的核心逻辑说明及扩展指导。

二、核心流程对比

端类型 授权方式 用户信息获取 注册信息存储 登录类型常量
公众号 code换取openid 调用getSnsUserInfo Redis缓存待绑定数据 THIRD_LOGIN_TOKEN_TYPE_PUBLIC
小程序 wx.login获取临时code 前端传昵称/头像 需前端补全信息 THIRD_LOGIN_TOKEN_TYPE_PROGRAM
APP(iOS/Android) 客户端SDK授权返回openid 客户端传递完整用户资料 直接携带资料缓存 THIRD_LOGIN_TOKEN_TYPE_IOS_WX / ANDROID_WX

三、关键代码说明

1.公共逻辑(所有端)

用户存在性检查
// 根据openid和类型查询绑定关系
UserToken userToken = userTokenService.getByOpenidAndType(openid, loginType);
if (userToken != null) {
    // 登录逻辑:更新最后登录时间、处理分销关系
    user.setLastLoginTime(now);
    transactionTemplate.execute(...); // ⚠️ 注意事务边界
} else {
    // 注册逻辑:缓存用户信息到Redis(key=MD5(openid))
    redisUtil.set(key, JSON.toJSONString(request), 120L, TimeUnit.MINUTES);
}

统一规则:
Redis键设计:MD5(openid)避免明文暴露;
注册数据有效期:固定120分钟(可配置化建议见下文)。

2. 公众号登录 (weChatAuthorizeLogin)

1.OAuth2授权流程
// 步骤1: 通过code获取access_token和openid
WeChatOauthToken oauthToken = wechatNewService.getOauth2AccessToken(code);
// 步骤2: 用access_token拉取用户详细信息
WeChatAuthorizeLoginUserInfoVo userInfo = 
wechatNewService.getSnsUserInfo(oauthToken.getAccessToken(), oauthToken.getOpenId());

依赖服务:
wechatNewService需实现微信API调用(如/sns/oauth2/access_token、/sns/userinfo);
错误处理:需捕获微信返回的errcode(如40029无效code)。

2.分销绑定逻辑
if (checkBingSpread(user, spreadUid, "old")) {
    user.setSpreadUid(spreadUid);
    userService.updateSpreadCountByUid(spreadUid, "add");
}
 /**
     * 检测能否绑定关系
     *
     * @param user      当前用户
     * @param spreadUid 推广员Uid
     * @param type      用户类型:new-新用户,old—老用户
     * @return Boolean
     * 1.判断分销功能是否启用
     * 2.判断分销模式
     * 3.根据不同的分销模式校验
     * 4.指定分销,只有分销员才可以分销,需要spreadUid是推广员才可以绑定
     * 5.人人分销,可以直接绑定
     * *推广关系绑定,下级不能绑定自己的上级为下级,A->B->A(❌)
     */
    public Boolean checkBingSpread(User user, Integer spreadUid, String type) {
        if (ObjectUtil.isNull(spreadUid)) {
            return false;
        }
        if (spreadUid <= 0 || user.getSpreadUid() > 0) {
            return false;
        }
        if (ObjectUtil.isNotNull(user.getUid()) && user.getUid().equals(spreadUid)) {
            return false;
        }
        // 判断分销功能是否启用
        String isOpen = systemConfigService.getValueByKey(Constants.CONFIG_KEY_STORE_BROKERAGE_IS_OPEN);
        if (StrUtil.isBlank(isOpen) || isOpen.equals("0")) {
            return false;
        }
        if (type.equals("old")) {
            // 判断分销关系绑定类型(所有、新用户)
            String bindType = systemConfigService.getValueByKey(Constants.CONFIG_KEY_DISTRIBUTION_TYPE);
            if (StrUtil.isBlank(bindType) || bindType.equals("1")) {
                return false;
            }
            if (user.getSpreadUid().equals(spreadUid)) {
                return false;
            }
        }
        // 查询推广员
        User spreadUser = getById(spreadUid);
        if (ObjectUtil.isNull(spreadUser) || !spreadUser.getStatus()) {
            return false;
        }
        // 指定分销不是推广员不绑定
        if (!spreadUser.getIsPromoter()) {
            return false;
        }
        // 下级不能绑定自己的上级为自己的下级
        if (ObjectUtil.isNotNull(user.getUid()) && spreadUser.getSpreadUid().equals(user.getUid())) {
            return false;
        }
        return true;
    }

3. 小程序登录 (weChatAuthorizeProgramLogin)

1.前端数据依赖
// 必须参数校验
if (StrUtil.isBlank(request.getNickName()) && ...) {
    loginResponse.setType("start"); // 要求前端补全信息
    return loginResponse;
}

设计约束:
小程序首次登录需前端提交nickName、avatar等(微信静默授权不返回这些信息);

2.SessionKey管理
// 通过code获取session_key和openid(内部实现)
WeChatMiniAuthorizeVo response = wechatNewService.miniAuthCode(code);

依赖服务:
wechatNewService需实现微信API调用(/sns/jscode2session)
通过code、appId、appSecret 认证获取session_key和openid

4. APP登录 (appLogin)

1.客户端参数直传
// 直接从请求体获取用户资料
registerThirdUserRequest.setOpenId(request.getOpenId());
registerThirdUserRequest.setAvatar(request.getAvatarUrl());
registerThirdUserRequest.setSex(request.getGender());
2.多平台区分
if (request.getType().equals(Constants.USER_LOGIN_TYPE_IOS_WX)) {
    userToken = userTokenService.getByOpenidAndType(openid, TYPE_IOS);
}
{{cateWiki.like_num}}人点赞
0人点赞
评论({{cateWiki.comment_num}}) {{commentWhere.order ? '评论从旧到新':'评论从新到旧'}} {{cateWiki.page_view_num}}人看过该文档
评论(0) {{commentWhere.order ? '评论从旧到新':'评论从新到旧'}} 1599人看过该文档
评论
{{item.user ? item.user.nickname : ''}} (自评)
{{item.content}}
{{item.create_time}} 删除
{{item.like ? item.like.like_num : 0}} {{replyIndex == index ? '取消回复' : '回复'}}
评论
{{items.user ? items.user.nickname : '暂无昵称'}} (自评)
{{items.content}}
{{items.create_time}} 删除
{{items.like ? items.like.like_num : 0}} {{replyIndexJ == (index+'|'+indexJ) ? '取消回复' : '回复'}}
评论
目录
  • {{item}}