文档目录
平台特定实现细节

简介

本文件聚焦 DouPHP 框架中各社交平台(微信、QQ、Google、Amazon)的 OAuth 登录实现差异,对比其 API 调用方式、参数配置、错误处理机制,并说明微信公众号与开放平台的区别处理、移动端与 PC 端适配方案。同时提供各平台配置参数说明、安全注意事项与性能优化建议,帮助开发者快速定位问题并正确集成。

项目结构

DouPHP 将第三方登录以“插件”形式组织,每个平台一个独立插件目录,包含 Provider(元数据与入口)、Service(业务逻辑)、可选 SDK 或脚本。统一通过 SnsLoginService 完成“绑定/自动注册/登录”的最终落地。

graph TB
subgraph "前端入口"
UI["用户点击登录"]
end
subgraph "插件层"
WX["微信登录插件<br/>WxloginProvider / WxloginService"]
QQ["QQ 登录插件<br/>QqService"]
GGL["Google 登录插件<br/>GoogleProvider / GoogleService"]
AMZ["Amazon 登录入口<br/>login.php"]
end
subgraph "统一协调"
SNS["SnsLoginService<br/>resolve()"]
end
UI --> WX
UI --> QQ
UI --> GGL
UI --> AMZ
WX --> SNS
QQ --> SNS
GGL --> SNS
AMZ --> SNS

核心组件

  • 微信登录插件(公众号/开放平台)
    • 通过 UA 判断是否在微信内,选择公众号授权页或开放平台扫码页;分别使用不同的 appid/appsecret。
    • 回调后校验 state,换取 access_token/openid,再拉取用户信息,最终交由 SnsLoginService 处理绑定/登录。
  • QQ 登录插件
    • 基于官方 SDK 完成 code 换 token、获取 openid 和用户信息,统一走 SnsLoginService。
  • Google 登录插件
    • 标准 OAuth 2.0/OpenID Connect:构造授权 URL、state 校验、code 换 token、Bearer 获取 userinfo,统一走 SnsLoginService。
  • Amazon 登录入口
    • 当前实现实际跳转至微信授权流程(用于兼容历史路径),在微信客户端与非微信客户端选择不同的授权地址。

架构总览

所有平台登录最终汇聚到统一的 SnsLoginService.resolve(),根据是否已绑定、是否已登录、配置项决定直接登录、跳转绑定页或自动注册。

sequenceDiagram
participant U as "用户浏览器/小程序"
participant P as "平台插件(微信/QQ/Google)"
participant O as "平台OAuth服务"
participant C as "SnsLoginService"
participant R as "路由/页面"
U->>P : 发起start()
P->>O : 重定向到授权页(state)
O-->>U : 回调带code/state
U->>P : finish(code,state)
P->>O : 用code换token/取用户信息
O-->>P : 返回openid/unionid/昵称等
P->>C : resolve(sns, userProfile, loginIdMode, nobind)
alt 已绑定且未登录
C-->>R : 跳转绑定页
else 已绑定且已登录
C-->>R : 直接登录并跳转用户中心
else 未绑定且允许nobind
C-->>R : 自动注册并登录
end

详细组件分析

微信登录(公众号 vs 开放平台)

  • 关键差异
    • 公众号(移动/微信内):UA 含 MicroMessenger,使用公众号 appid/appsecret,授权 scope=snsapi_userinfo。
    • 开放平台(PC 扫码):非微信 UA,使用开放平台 appid/appsecret,授权 scope=snsapi_login。
  • 回调处理
    • 校验 state,换取 access_token/openid,必要时检查 unionid(按配置)。
    • 构建 sns 对象(group=wxlogin, apptype=weixin),交由 SnsLoginService 处理。
  • 移动端与 PC 端适配
    • 同一插件通过 UA 自动区分,无需前端额外判断。
  • 小程序侧补充
    • 小程序登录走 api/controller/user/WeixinController,使用 jscode2session,与 PC 插件流程分离。
flowchart TD
Start(["开始"]) --> UA{"是否微信UA?"}
UA -- 是 --> MP["公众号授权<br/>scope=snsapi_userinfo"]
UA -- 否 --> OP["开放平台扫码<br/>scope=snsapi_login"]
MP --> CB["回调校验state+code"]
OP --> CB
CB --> Token["换取access_token/openid"]
Token --> Info["拉取用户信息(含unionid可选)"]
Info --> Resolve["SnsLoginService.resolve()"]
Resolve --> End(["结束"])

QQ 登录

  • 授权与回调
    • start() 生成 state 并存入会话,构造 graph.qq.com 授权 URL。
    • finish() 加载 SDK,调用 qq_callback() 获取 accessToken 与 openid,再取用户信息。
  • 数据映射
    • 将 nickname、头像、性别等映射为统一 sns 结构,交由 SnsLoginService 处理。
  • 配置
    • 需要 appid 与 appkey,并在插件配置中设置回调地址。
sequenceDiagram
participant U as "用户"
participant Q as "QqService"
participant SDK as "QQ SDK"
participant S as "SnsLoginService"
U->>Q : start()
Q-->>U : 重定向到QQ授权页
U-->>Q : 回调finish(code)
Q->>SDK : qq_callback() + get_openid()
SDK-->>Q : accessToken, openid
Q->>SDK : get_user_info()
SDK-->>Q : 用户信息
Q->>S : resolve(sns, profile, 'openid', false)
S-->>U : 登录/绑定/注册结果

Google 登录

  • 授权与回调
    • start() 生成 state 存入 Session,构造 accounts.google.com 授权 URL(scope=openid email profile)。
    • finish() 校验 state,用 code 换 access_token,再用 Bearer 获取 userinfo(sub 作为唯一标识)。
  • 数据映射
    • 将 name/picture 等映射为统一 sns 结构,sex 默认空值。
  • 配置
    • 需要 client_id 与 client_secret,回调地址需在 Google Cloud Console 中注册。
sequenceDiagram
participant U as "用户"
participant G as "GoogleService"
participant GO as "Google OAuth"
participant S as "SnsLoginService"
U->>G : start()
G-->>U : 重定向到Google授权页
U-->>G : 回调finish(code,state)
G->>GO : POST /token (code)
GO-->>G : access_token
G->>GO : GET /userinfo (Bearer)
GO-->>G : {sub, name, picture...}
G->>S : resolve(sns, profile, 'openid', false)
S-->>U : 登录/绑定/注册结果

Amazon 登录入口(当前实现)

  • 行为说明
    • 该入口实际跳转到微信授权流程,并根据 UA 选择公众号或开放平台授权页。
    • 适用于历史兼容场景,不建议在新项目中直接使用。
  • 建议
    • 如需接入 Amazon OAuth,应新建独立插件并按 Google/QQ 模式实现。

依赖关系分析

  • 插件与服务
    • 微信/QQ/Google 插件均依赖 SnsLoginService 进行最终的用户绑定/登录决策。
    • 微信插件还依赖配置项(param.login_mode、param.loginid_mode)控制行为。
  • 外部依赖
    • 微信:open.weixin.qq.com(授权)、api.weixin.qq.com(token/userinfo)。
    • QQ:graph.qq.com(授权)、官方 SDK。
    • Google:accounts.google.com(授权)、oauth2.googleapis.com(token)、www.googleapis.com(userinfo)。
graph LR
WX["微信插件"] --> SNS["SnsLoginService"]
QQ["QQ插件"] --> SNS
GGL["Google插件"] --> SNS
WX --> WXAPI["微信API"]
QQ --> QQAPI["QQ接口/SDK"]
GGL --> GAPI["Google OAuth API"]

性能考虑

  • 网络请求
    • 微信/Google 均涉及多次 HTTP 调用(授权、换 token、取用户信息),建议在服务器侧启用连接复用与超时控制。
  • 状态校验
    • 使用 state 防 CSRF,避免重复计算与无效回调。
  • 缓存策略
    • 对频繁访问的用户信息可短期缓存(注意隐私与过期时间)。
  • 限流与重试
    • 对第三方 API 失败做指数退避重试,避免雪崩。

故障排查指南

  • 常见错误与定位
    • state 不匹配:检查 Session 是否被清理或跨域导致丢失。
    • 无法获取 code:确认回调地址与平台后台一致,且未被拦截。
    • 无法获取用户信息:检查 token 是否有效、scope 是否足够。
    • unionid 缺失:当配置要求 unionid 时,需确保平台返回 unionid。
  • 日志与审计
    • 微信登录失败会记录审计日志(如 code 无效、unionid 缺失)。
    • 管理员登录失败有明确审计分类,便于排查。

结论

DouPHP 通过插件化设计将不同平台的 OAuth 登录统一到 SnsLoginService,简化了多平台接入与维护。微信插件支持公众号与开放平台双模式,QQ 与 Google 遵循各自平台规范。Amazon 入口当前为历史兼容实现。建议新项目优先采用微信/QQ/Google 的标准插件,并严格遵循配置与安全最佳实践。

附录:配置参数与常见问题

微信登录(插件)

  • 配置字段
    • APPID(微信开放平台):用于 PC 扫码登录。
    • APPSECRET(微信开放平台):与开放平台 APPID 配对。
    • APPID(微信公众号):用于微信内自动登录。
    • APPSECRET(微信公众号):与公众号 APPID 配对。
  • 常见问题
    • 回调地址不一致:需在对应平台后台配置完全一致的回调地址。
    • unionid 缺失:若配置要求 unionid,请确保平台返回 unionid。
    • UA 识别异常:确认请求头中包含 MicroMessenger 以进入公众号流程。

QQ 登录(插件)

  • 配置字段
    • appid:QQ 开放平台应用 ID。
    • appkey:与 appid 配对的密钥。
  • 常见问题
    • SDK 初始化失败:检查全局 connect_inc 配置是否正确注入。
    • 权限不足:确保 scope 包含 get_user_info。

Google 登录(插件)

  • 配置字段
    • Client ID:Google OAuth 2.0 客户端 ID。
    • Client Secret:与 Client ID 配对的密钥。
  • 常见问题
    • 回调地址未注册:需在 Google Cloud Console 中添加回调地址。
    • scope 不足:确保包含 openid、email、profile。

Amazon 登录(入口)

  • 现状说明
    • 当前实现跳转至微信授权流程,并非真正的 Amazon OAuth。
  • 建议
    • 如需接入 Amazon OAuth,请按 Google/QQ 模式新建插件。

小程序微信登录(API)

  • 流程说明
    • 前端 wx.login 获取 code,后端调用 jscode2session 获取 openid/session_key,再完成绑定/登录。
  • 常见问题
    • code 无效:确认 code 仅一次使用且在有效期内。
    • unionid 缺失:当配置要求 unionid 时需确保平台返回。
添加日期:2026-10-05