三方登录
这篇解决什么
用钉钉、企业微信等平台的账号进管理后台,或用微信公众号 / 小程序进用户 App。读完能配客户端、走绑定登录与快捷登录,以及在个人中心解绑。
默认端口 48080,管理端前缀 /admin-api。PC 开发页 http://127.0.0.1:5800。三方登录发的仍是本系统 Token,权限模型不变。
示意图:浏览器先拿第三方授权码,再由 system 换成自己的访问令牌。
| 名称 | 说明 | 仓库路径 |
|---|---|---|
| 管理端登录 | 钉钉、企业微信扫码 | ruoyi-office-vben/apps/web-antd/src/views/_core/authentication/ |
| 用户 App | 微信公众号、微信小程序等 | ruoyi-office/yudao-module-member/ |
| 社交用户 | 落库三方身份 | ruoyi-office/yudao-module-system/ |
登录怎么走
管理端点钉钉或企业微信后,先换第三方授权地址,扫码回来再尝试快捷登录。未绑定时要再用账号密码做一次绑定登录。
示意图:按 AuthController 与 social-login.vue 的真实顺序。
| 名称 | 说明 | 仓库路径 |
|---|---|---|
| 授权跳转 | @PermitAll,GET /social-auth-redirect,固定 userType = ADMIN | ruoyi-office/yudao-module-system/.../controller/admin/auth/AuthController.java |
| 快捷登录 | POST /social-login,已绑定才发 Token | 同上 |
| 绑定登录 | POST /login,账号密码外再带社交三参数 | 同上;AdminAuthServiceImpl#login |
| 登录页 | @third-login 调 socialAuthRedirect | ruoyi-office-vben/apps/web-antd/src/views/_core/authentication/login.vue |
| 回调页 | 先快捷登录,失败后显示账号密码 | .../authentication/social-login.vue |
| 前端 API | socialAuthRedirect / socialLogin | ruoyi-office-vben/apps/web-antd/src/api/core/auth.ts |
登录页图标里,企微传 type = 30,钉钉传 20。QQ、GitHub 传 0,handleThirdLogin 直接返回,不会发请求。
回调地址要先 encodeURIComponent 一次,再拼进 redirectUri。钉钉回跳时会丢掉未编码的 query。
授权码为什么要落库
code 只能向第三方换一次。快捷登录失败后,绑定登录还要用同一组 code + state。SocialUserServiceImpl#authSocialUser 先按 type + code + state 查库,有记录就不再打第三方。
管理端不会自动开户
快捷登录找不到绑定用户时,抛 AUTH_THIRD_LOGIN_NOT_BIND(「未绑定账号,需要进行绑定」)。必须先有本系统账号。用户 App 相反:未绑定会先建会员再绑定。
绑定与解绑
已登录用户在个人中心「社交绑定」里,把当前账号挂到某个平台,或解开。
| 名称 | 说明 | 仓库路径 |
|---|---|---|
| 绑定 | POST /system/social-user/bind,用当前登录用户 | .../controller/admin/socail/SocialUserController.java |
| 解绑 | DELETE /system/social-user/unbind,按 type + openid | 同上 |
| 已绑列表 | GET /system/social-user/get-bind-list | 同上 |
| 个人中心 | Tab「社交绑定」 | ruoyi-office-vben/apps/web-antd/src/views/_core/profile/modules/user-social.vue |
| 绑定回调 | 回 {origin}/profile?type=...,再带 code / state | user-social.vue 的 onBind / bindSocial |
第三方平台若要配授信域名,至少加两处:/auth/social-login(登录回调)、/profile(绑定回调)。
bindSocialUser 会先清掉两类旧关系:同一社交用户挂过的其它本端用户,以及当前用户已绑的同一平台。同一 userType 下,一个用户对一个平台只留一条绑定。

本系统截图:个人中心 → 社交绑定。
表与关键类
三张表:客户端配置、三方用户、与本系统用户的绑定。
按本仓库 DO 生成的 ER。客户端按租户隔离;用户与绑定表继承 BaseDO,没有 tenant_id。
| 名称 | 说明 | 仓库路径 |
|---|---|---|
SocialClientDO | 表 system_social_client,继承 TenantBaseDO | .../dal/dataobject/social/SocialClientDO.java |
SocialUserDO | 表 system_social_user。type 是平台,openid 来自 JustAuth 的 uuid | .../dal/dataobject/social/SocialUserDO.java |
SocialUserBindDO | 表 system_social_user_bind。userType 区分管理端 / 会员 | .../dal/dataobject/social/SocialUserBindDO.java |
SocialTypeEnum | 平台编号与 JustAuth source | yudao-module-system-api/.../enums/social/SocialTypeEnum.java |
UserTypeEnum | MEMBER = 1,ADMIN = 2 | yudao-framework/yudao-common/.../enums/UserTypeEnum.java |
SocialClientServiceImpl | 拼授权 URL、用 code 换用户、buildAuthRequest | .../service/social/SocialClientServiceImpl.java |
SocialUserServiceImpl | 认证、绑定、解绑、按 code 查绑定用户 | .../service/social/SocialUserServiceImpl.java |
social_type 与枚举对应:
| 名称 | 说明 | 仓库路径 |
|---|---|---|
10 / GITEE | Gitee | SocialTypeEnum.GITEE |
20 / DINGTALK | 钉钉 | SocialTypeEnum.DINGTALK |
30 / WECHAT_ENTERPRISE | 企业微信 | SocialTypeEnum.WECHAT_ENTERPRISE |
31 / WECHAT_MP | 微信公众号 H5 | SocialTypeEnum.WECHAT_MP |
32 / WECHAT_OPEN | 微信开放平台网站应用 | SocialTypeEnum.WECHAT_OPEN |
34 / WECHAT_MINI_PROGRAM | 微信小程序 | SocialTypeEnum.WECHAT_MINI_PROGRAM |
40 / ALIPAY | 支付宝小程序,库里 public_key | SocialTypeEnum.ALIPAY_MINI_PROGRAM |
非显而易见字段:agentId 给企业微信网页应用;publicKey 给支付宝;rawTokenInfo / rawUserInfo 存第三方原始 JSON。socialType 在绑定表里冗余,方便按平台查。
配置
JustAuth 先读 yaml,库里有启用中的客户端再覆盖 clientId / clientSecret / agentId。
| 名称 | 说明 | 仓库路径 |
|---|---|---|
| yaml | justauth.enabled、justauth.type.* | ruoyi-office/yudao-server/src/main/resources/application-dev.yaml |
| 装配 | justauth.enabled=true 才建 AuthRequestFactory | .../framework/justauth/config/YudaoJustAuthConfiguration.java |
| Redis state | 前缀 social_auth_state:,默认 24h | 同 yaml 的 justauth.cache |
| 覆盖逻辑 | 启用的库配置优先生效 | SocialClientServiceImpl#buildAuthRequest |
| 唯一约束 | 同一租户下 userType + socialType 只能一条 | validateSocialClientUnique,错误码 SOCIAL_CLIENT_UNIQUE |
justauth:
enabled: true
type:
DINGTALK:
client-id: ${DINGTALK_CLIENT_ID}
client-secret: ${DINGTALK_CLIENT_SECRET}
ignore-check-redirect-uri: true
WECHAT_ENTERPRISE:
client-id: ${WECOM_CLIENT_ID}
client-secret: ${WECOM_CLIENT_SECRET}
agent-id: ${WECOM_AGENT_ID}
ignore-check-redirect-uri: true
WECHAT_MINI_PROGRAM:
client-id: ${wx.miniapp.appid}
client-secret: ${wx.miniapp.secret}
ignore-check-redirect-uri: true
ignore-check-state: true
WECHAT_MP:
client-id: ${wx.mp.app-id}
client-secret: ${wx.mp.secret}
ignore-check-redirect-uri: true
ALIPAY:
client-id: ${ALIPAY_APP_ID}
client-secret: ${ALIPAY_APP_SECRET}
alipay-public-key: ${ALIPAY_PUBLIC_KEY}
ignore-check-redirect-uri: true
ignore-check-state: true
cache:
type: REDIS
prefix: 'social_auth_state:'
timeout: 24h密钥写环境变量或本机私有配置,不要把示例 App 提交进文档。接新平台时,在 SocialTypeEnum 加类型,并在 justauth.type 下用 JustAuth 的 source 名补一段。
平台申请看官方文档:钉钉、企业微信、JustAuth 各平台说明。
一套租户不能并排两套同平台配置
查询键是 socialType + userType(再加租户)。同一租户、同一端、同一平台只能有一条启用配置。要按「应用」再拆,需要自己加隔离字段,并让前端把该字段传到 buildAuthRequest。
菜单与管理页
「系统管理 → 三方登录」下两页:三方应用改当前租户的客户端,三方用户只读查询。
| 名称 | 说明 | 仓库路径 |
|---|---|---|
| 目录 | 菜单 id 2447,路由 /system/social | system_menu |
| 三方应用 | id 2448,组件 system/social/client/index.vue | ruoyi-office-vben/apps/web-antd/src/views/system/social/client/ |
| 三方用户 | id 2453,权限 system:social-user:query | .../views/system/social/user/ |
| 应用 API | /system/social-client,创建/改/删要 system:social-client:* | .../controller/admin/socail/SocialClientController.java |
| 用户查询 | /system/social-user/page、/get | SocialUserController |
| 移动端 | 三方用户列表 | ruoyi-office-uniapp/src/pages-system/social/ |
官方菜单 id 用 1–9999。客户端表单里,企业微信才显示 agentId,支付宝才显示 publicKey。

本系统截图:系统管理 → 三方登录 → 三方应用。

本系统截图:系统管理 → 三方登录 → 三方用户。
用户 App
会员走同一套社交表,只是 userType = MEMBER。未绑定会先建会员再绑,不必先有账号。
| 名称 | 说明 | 仓库路径 |
|---|---|---|
| 授权 / 快捷登录 | /member/auth/social-auth-redirect、/social-login | .../controller/app/auth/AppAuthController.java |
| 绑定 / 解绑 | /member/social-user | .../controller/app/social/AppSocialUserController.java |
| 实现 | 未绑定则 createUser 再 bindSocialUser | .../service/auth/MemberAuthServiceImpl.java |
| 模块间调用 | SocialUserApi / SocialClientApi | yudao-module-system-api/.../api/social/ |
小程序手机号登录、订阅消息、发货信息走 SocialClientService 里微信专用方法,不是 JustAuth 扫码这条链。
扩展时注意
| 名称 | 说明 | 仓库路径 |
|---|---|---|
| 登录页平台 | 只把 20 / 30 接到 handleThirdLogin | third-party-login.vue |
| 个人中心卡片 | 同样只列钉钉、企微 | SystemUserSocialTypeEnum |
| 字典 | 列表展示用 system_social_type | DICT_TYPE.SYSTEM_SOCIAL_TYPE |
| 错误码 | SOCIAL_USER_AUTH_FAILURE、SOCIAL_CLIENT_NOT_EXISTS | ErrorCodeConstants |
要在登录页加微信开放平台,前端要传 32,并保证库或 yaml 里有对应客户端。type = 0 的图标只是占位。
三方登录解决的是「用谁的身份进来」。对外提供本系统的授权码与令牌,见 OAuth 2.0。
配置与操作
管理员在 系统管理 → 三方登录 → 三方应用 填 type、clientId、密钥、回调。保存后登录页对应按钮才能换码。三方用户页只看绑定,个人中心解绑。
type 必须和前端传入的社交类型一致,例如微信开放平台 32。yaml 里的客户端是兜底,库表优先。开启见 系统功能设计。截图见上文客户端和用户列表。
