本文档是基本自己的项目,基本实现逻辑一致
基于 JustAuth 开源组件的三种微信登录形态集成说明(微信开放平台、微信公众平台、小程序等)
目录
一、前提准备:应用注册
二、整体架构概览
三、技术栈与依赖
四、JustAuth 框架封装说明
五、全局配置
六、方式一:公众号扫码登录(PC/普通浏览器)
七、方式二:微信开放平台快捷登录(H5/App 快捷登录)
八、方式三:微信浏览器内静默授权(无感知获取 openid)
九、注意事项与常见问题
一、前提准备:应用注册
在对接任何一种微信登录之前,必须先在微信官方平台申请相应应用,并拿到以下关键凭证:
| 平台 | 申请入口 | 用途 | 关键凭证 |
|---|---|---|---|
| 微信公众平台 | https://mp.weixin.qq.com | 公众号扫码登录 + 微信内静默授权 | AppID、AppSecret |
| 微信开放平台 | https://open.weixin.qq.com | 快捷登录(微信内 H5、App 拉起微信授权) | AppID、AppSecret |
| 微信开放平台 →网站应用 | 开放平台内 → 创建应用 → 网站应用 | PC 网站扫码登录 | AppID、AppSecret |
注册后必须配置的白名单
| 登录方式 | 需配置的白名单 | 位置 |
|---|---|---|
| 公众号扫码登录 | 网页授权域名(不带协议、不带路径) | 公众平台 → 开发 → 基本配置 → 公众号设置 → 功能设置 |
| 开放平台快捷登录 | 授权回调域 | 开放平台 → 应用详情 → 网站信息 → 授权回调域 |
| 微信内静默授权 | 网页授权域名(同公众号扫码) | 同公众号扫码 |
重要:微信白名单不支持 localhost / 127.0.0.1,本地调试需配 hosts 虚拟域名 + Nginx 反代。
二、整体架构概览
三种方式的核心差异
| 对比项 | 方式一:公众号扫码 | 方式二:开放平台快捷 | 方式三:静默授权 |
|---|---|---|---|
| 适用终端 | PC、普通浏览器 | H5、App、PC | 仅微信内浏览器 |
| 微信平台 | 公众平台 | 开放平台 | 公众平台 |
| JustAuth 请求类 | AuthWeChatMpRequest | AuthWeChatOpenRequest | AuthWeChatMpRequest(仅换 openid) |
| 前端是否展示二维码 | ✅ 是 | ❌ 否(前端调起授权) | ❌ 否(静默) |
| 前端角色 | 轮询等待扫码结果 | 回调后直接拿 code | 仅触发跳转,后端静默获取 |
| 最终目的 | 获取微信用户完整信息 → 登录 | 获取微信用户完整信息 → 登录 | 仅获取 openid→ 用于支付等场景 |
三、技术栈与依赖
| 技术 | 说明 |
|---|---|
| JDK | 17 |
| 框架 | Spring Boot |
| ORM | MyBatis-Plus |
| 三方登录核心 | JustAuth(me.zhyd.oauth) |
| 缓存 | Redis |
| 登录态管理 | Sa-Token |
| 工具 | Hutool(Base64、JSON 等) |
四、JustAuth 框架封装说明
本项目通过SocialUtils对 JustAuth 进行了统一封装,屏蔽了各平台的差异。
4.1 核心类关系
4.2 SocialUtils 支持的 source 值
以下为与微信相关的三种 source(完整支持列表见源码 switch-case):
| source | JustAuth 实现 | 微信平台 | 用途 |
|---|---|---|---|
wechat_mp | AuthWeChatMpRequest | 公众平台 | 公众号扫码 + 静默授权 |
wechat_open | AuthWeChatOpenRequest | 开放平台 | 快捷登录(H5 / App / 网站) |
五、全局配置
5.1 application.yml 配置结构
# ====== JustAuth 三方登录配置 ====== justauth: # 前端外网访问基址(用于拼接 redirectUri) address: https://your-domain.com # 各平台独立配置 type: # --- 微信开放平台:快捷登录 --- wechat_open: client-id: wx开放平台AppID client-secret: wx开放平台AppSecret # 后端回调接口(本项目定义) redirect-uri: ${justauth.address}/auth/social/wechatOpen?source=wechat_open # --- 微信公众平台:公众号扫码 + 静默授权 --- wechat_mp: client-id: wx公众号AppID client-secret: wx公众号AppSecret # 公众号扫码登录的回调(方式一使用) redirect-uri: ${justauth.address}/auth/social/callback?source=wechat_mp5.2 额外配置项
# 静默授权成功后,服务端重定向的首页地址 # 来源:数据库 sys_dict_data 或 sys_config 表 # key = wx.auth.redirect.url
5.3 配置类绑定
前缀
justauth→SocialProperties(带@ConfigurationProperties)justauth.type.*→Map<String, SocialLoginConfigProperties>
六、方式一:公众号扫码登录(PC/普通浏览器)
核心流程:服务端拼接授权地址 → 前端生成二维码 → 用户扫码 → 微信回调后端 →前端轮询Redis 获取结果 → 调用统一登录接口
6.1 时序图
6.2 涉及接口清单
| # | 接口 | 方法 | 调用方 | 说明 |
|---|---|---|---|---|
| 1 | /auth/binding/wechat_mp | GET | 前端 | 生成微信 authorizeUrl + uuid |
| 2 | /auth/social/callback | GET | 微信服务器 | 扫码授权回调,code 换 AuthUser,写 Redis |
| 3 | /auth/scanCodeRes | GET | 前端(轮询) | 根据 uuid 读取 Redis 中的扫码结果 |
| 4 | /auth/login | POST | 前端(拿结果后) | 统一登录入口,grantType=social |
6.3 关键接口详细说明
① 生成扫码 URL
GET /auth/binding/{source}?domain={domain} source=wechat_mp请求参数:
| 参数 | 类型 | 必传 | 说明 |
|---|---|---|---|
| source | String | 是 | 固定wechat_mp |
| domain | String | 是 | 前端当前域名(用于后续前端回跳) |
返回示例:
state里面是自定义参数。redirect_uri跳转地址(服务端,需要和配置的域名一致)
{ "code": 200, "msg": "操作成功", "data": { "uuid": "e9cbbe619d7823493469ae83d477ee40", "authorizeUrl": "https://open.weixin.qq.com/connect/oauth2/authorize?appid=wxd761ef931d1a57de&redirect_uri=https%3A%2F%2Fecc.waper.com.cn%2Fwp3dmall%2Fauth%2Fsocial%2Fcallback%3Fsource%3Dwechat_mp&response_type=code&scope=snsapi_userinfo&state=eyJkb21haW4iNuIiwic3RhdGUiOiJlOWNiYmU2MTlkNzgyMzQ5MzQ2OWFlODNkNDc3ZWU0MCJ9#wechat_redirect", "state": "eyJkb21haW4iNuIiwic3RhdGUiOiJlOWNiYmU2MTlkNzgyMzQ5MzQ2OWFlODNkNDc3ZWU0MCJ9" }, "isExpired": false }② 微信扫码回调
GET /auth/social/callback?source=wechat_mp&code={code}&state={state}此接口由微信服务器主动回调,前端不直接调用。
后端处理:
Base64 解码
state→ 拿到内部uuidSocialUtils.loginAuth("wechat_mp", code, state, properties)→ JustAuth 内部完成:code → access_token → 刷新 access_token → 用户信息
最终返回
AuthUser(含 uuid / nickname / avatar / openid 等)
RedisUtils.setCacheObject(SOCIAL_USER + uuid, AuthUser, 10min)— 存完整用户信息RedisUtils.setCacheObject(SOCIAL_LOGIN + uuid, SocialLoginBody, 10min)— 存登录参数返回成功 HTML 页面(用户扫码后看到"扫码成功,请关闭此页面")
③ 前端轮询扫码结果
GET /auth/scanCodeRes?uuid={uuid}返回:
未扫码 / 未授权:
R.ok(null, false)已授权:
R.ok(socialLoginBody)— data 为SocialLoginBody对象
SocialLoginBody 字段:
| 字段 | 类型 | 说明 |
|---|---|---|
| source | String | 固定wechat_mp |
| socialCode | String | 微信 code |
| socialState | String | 微信 state(Base64 编码) |
| phonenumber | String | 绑定手机号时传 |
| bindUser | boolean | 是否已绑定系统用户 |
| uuid | String | 本次扫码唯一标识 |
七、方式二:微信开放平台快捷登录(PC 网页快捷登录系统)
实现效果(当无法识别微信是否登录时,或浏览器不支持时,会以二维码的形式进行授权登录)
核心流程:前端拿到 code → 调后端换用户信息 → 后端写 Redis 并直接返回 → 前端走统一登录接口
7.1 时序图
7.2 涉及接口清单
| # | 接口 | 方法 | 调用方 | 说明 |
|---|---|---|---|---|
| 1 | /auth/binding/wechat_open(可选) | GET | 前端 | 生成 authorizeUrl(也可前端直接调微信,这里主要是) |
| 2 | /auth/social/wechatOpen | GET | 前端 | 核心接口:code 换 AuthUser + 写 Redis + 直接返回 SocialLoginBody |
| 3 | /auth/login | POST | 前端 | 统一登录入口 |
7.3 wechatOpen 接口特点
与方式一回调接口的关键差异:
| 对比项 | 方式一 callback | 方式二 wechatOpen |
|---|---|---|
| 调用方 | 微信服务器(浏览器302跳转) | 前端 JS(XHR/fetch) |
| 返回类型 | 返回 HTML 页面 | 返回 JSON 对象R.ok(socialLoginBody) |
| 前端体验 | 需轮询 + 关闭浏览器 | 同步等待即可,拿到 SocialLoginBody 直接调 login |
| 适用 | PC 扫码场景 | H5/App 快捷授权场景 |
八、方式三:微信浏览器内静默授权(无感知获取 openid)
适用场景:用户在微信内浏览器打开系统链接,需要无感知拿到 openid(用于后续支付等场景),不做登录。
核心流程:前端拿 authorizeUrl → 微信静默授权(scope=snsapi_base)→ 后端回调 code 换 openid → Redis 存 openid → 服务端重定向到系统首页
8.1 时序图
8.2 涉及接口清单
| # | 接口 | 方法 | 调用方 | 说明 |
|---|---|---|---|---|
| 1 | /auth/social/getCallbackUrl | GET | 前端 | 生成静默授权 authorizeUrl + state |
| 2 | /auth/social/callback/getAuth | GET | 微信服务器 | code 换 openid,写 Redis,重定向首页 |
| 3 | /auth/social/getOpenId | GET | 前端(登录后) | 根据 state 从 Redis 取 openid |
8.3 getCallbackUrl 接口细节
GET /auth/social/getCallbackUrl
无请求参数,内部固定使用wechat_mp配置 +snsapi_base作用域。
返回:
{ "code": 0, "msg": null, "data": { "authorizeUrl": "https://open.weixin.qq.com/connect/oauth2/authorize?appid=...&redirect_uri=...&response_type=code&scope=snsapi_base&state=...#wechat_redirect", "state": "MWIyYzNkNGU1ZjY3ODkA", "appId": "公众号 AppID" } }8.4 与方式一/二的关键差异
| 对比项 | 方式三(静默授权) | 方式一/二(扫码/快捷登录) |
|---|---|---|
| scope | snsapi_base(仅 openid) | snsapi_userinfo(用户完整信息) |
| JustAuth 调用 | gerAccessToken() | loginAuth() |
| Redis Key | SOCIAL_AUTH:{state} | SOCIAL_USER:{uuid}+SOCIAL_LOGIN:{uuid} |
| 最终目的 | 拿 openid | 拿用户信息 → 登录系统 |
| 前端后续动作 | 首页加载后调getOpenId | 调/auth/login |
| 是否需要登录 | 取 openid 时需要已登录 | 登录前调用 |
九、注意事项与常见问题
9.1 redirect_uri 编码
JustAuth 内部会处理 redirect_uri 的编码,但微信官方要求回调地址必须与注册时的完全一致(包括 query 参数)。
排错技巧:回调失败先检查 redirect_uri 在微信后台注册的是否和配置文件
justauth.type.*.redirect-uri完全一致。
9.2 state 防 CSRF
JustAuth 自带 state 校验机制(AuthRedisStateCache):
生成 authorizeUrl 时写入 Redis
回调时自动比对
过期时间与授权时间保持一致
9.3 三种方式的使用边界
| 场景 | 推荐方式 | 原因 |
|---|---|---|
| PC 网页登录 | 方式一公众号扫码 | PC 没有微信 App,只能扫码 |
| H5 登录(浏览器中) | 方式二开放平台 | 开放平台快捷授权体验更好 |
| App 拉起微信登录 | 方式二开放平台 | 开放平台支持 App 端拉起微信 SDK |
| 微信内浏览器无感知拿 openid | 方式三静默授权 | 唯一能在微信内静默拿 openid 的方式 |
| 微信内浏览器登录 | 方式二开放平台 + App 授权 | 开放平台授权后直接回传用户信息 |
9.4 本地调试方案
微信白名单不支持 localhost,推荐方案:
# hosts 127.0.0.1 your-test-domain.com
Nginx 反代 (HTTPS)
server { listen 443 ssl; server_name your-test-domain.com; ssl_certificate ...;
location / { proxy_pass http://127.0.0.1:8080; }}
然后把justauth.address改为https://your-test-domain.com。
9.5 JustAuth getAccessToken 与 loginAuth 对比
| 方法 | 微信接口 | 返回内容 | 适用 |
|---|---|---|---|
getAccessToken() | /sns/oauth2/access_token | AuthToken(access_token、openid、refresh_token、expireIn) | 只需要 openid |
login() | /sns/oauth2/access_token + /sns/userinfo | AuthUser(uuid、nickname、avatar、openid + token) | 需要完整用户信息做登录 |
9.6 跨平台统一用户(unionid)
当用户同时关注公众号、使用开放平台应用时,微信通过unionid识别同一用户。JustAuth 返回的AuthUser.uuid优先取 unionid(如果配置了unionId: true),否则取 openid。
建议在
wechat_open和wechat_mp配置中都开启unionId: true,以确保多端登录识别到同一用户。